在列表中递增和使用时,python3 datetime对象行为问题

时间:2018-11-18 00:32:52

标签: python-3.x datetime

我正在使用PyEphem计算卫星的轨道位置,但是除了实际的PyEphem代码之外,我所遇到的问题也很明显,因此我简化了示例,但不包括任何pyephem代码。但是,出于项目上下文的考虑……在每个循环中,递增的calcDT用于计算该新calcDT的卫星通行细节,所有这些都将存储在列表中,以供以后分析和绘图,取回I期望我实际上已经添加到列表中了。

涉及三个日期时间对象。上升时间,设置时间和计算时间,分别为riseDT,setDT和calcDT。 riseDT和setDT根本不应更改。他们不。 calc_DT在每个循环中步进。然后,将calcDT与setDT进行相等性检查,以查看传递是否结束。我已经使用.id()来查看(并显示)何时何地被引用了哪些内存位置,显然表明“循环列表中的” calcDT恢复为引用riseDT“对象(及其对象)的内存位置值”),当我实际上希望它引用一个全新的calcDT递增的“值”时,它会首先创建calcDT。

这是演示问题的完整代码。特别要注意的是,在最后三个结果块中,即使独立的var版本适当不同且正确,列表中的riseDT和calcDT值也是相同的(不应相同)。 :

import datetime


riseDT = datetime.datetime(2018, 11, 13, 5, 30, 0, 0)
setDT = datetime.datetime(2018, 11, 13, 5, 30, 1, 500000)
calcDT = riseDT
stepS = 0.5

fullPassList = []

print('==============================================')
print('riseDT before loop :', riseDT)
print('riseDT id()        :', id(riseDT))
print('calcDT before loop :', calcDT)
print('calcDT id()        :', id(calcDT))
print('note that both are referencing the same memory')
print('==============================================')
print('riseDT before loop :', riseDT)
print('riseDT id()        :', id(riseDT))
print('attempt to force an independent calcDT created')
print('with the value only of riseDT by using the')
print('.replace method with no change specified.')
calcDT = riseDT.replace()
print('calcDT before loop :', calcDT)
print('calcDT id()        :', id(calcDT))
print('It worked before the loop, but issues inside it?')
print('==============================================')
print('Still alright after putting them into a list?')
fullPassList.append(riseDT)                       # index   [0]
fullPassList.append(stepS)                        # index   [1]
fullPassList.append(calcDT)                       # index   [2]
print('riseDT before loop, in list :', fullPassList[0])
print('riseDT id()        : ', id(fullPassList[0]))
print('stepS  before loop, in list :', fullPassList[1])
print('stepS  id()        : ', id(fullPassList[1]))
print('calcDT before loop, in list :', fullPassList[2])
print('calcDT id()        : ', id(fullPassList[2]))
print('==============================================')
print('==============================================')

while calcDT <= setDT:    # should show 4 result sets

    print('riseDT inside loop :', riseDT)
    print('riseDT id()        :', id(riseDT))
    print('calcDT inside loop :', calcDT, ' alright as a var')
    print('calcDT id()        :', id(calcDT))
    print('Looks alright here, but put them in a list ...')
    print('- - - - - - - - - - - - - - - - - - - - - - - ')

    # pyephem code start
    #  does stuff but irrelevant to issue
    # pyephem code end

    print('Still alright after putting them into a list?')
    # No.  calcDT goes back to referencing the memory location of riseDT
    # when calcDT is put into a list and then accessed in the list.
    fullPassList.append(riseDT)                       # index   [0]
    fullPassList.append(stepS)                        # index   [1]
    fullPassList.append(calcDT)                       # index   [2]
    print('riseDT inside loop, in a list :', fullPassList[0])
    print('riseDT id()        : ', id(fullPassList[0]))
    print('stepS  inside loop, in a list :', fullPassList[1])
    print('stepS  id()        : ', id(fullPassList[1]))
    print('calcDT inside loop, in a list :', fullPassList[2], ' NG in list?')
    print('calcDT id()        : ', id(fullPassList[2]))
    print('----------------------------------------------')

    calcDT += datetime.timedelta(seconds=stepS)

这是运行此代码的结果,显示了此问题。我可以在东芝L775 Ubuntu 18.04LTS(无venv)和python 3.6.5上,以及在venv中使用本地编译的python 3.7.0的多个raspberry pi 3B + Raspbian Stretch上,一贯地复制该问题。可以看出结果始终是不希望有的,这里在rpi 3B +上运行:

==============================================
riseDT before loop : 2018-11-13 05:30:00
riseDT id()        : 1990840856
calcDT before loop : 2018-11-13 05:30:00
calcDT id()        : 1990840856
note that both are referencing the same memory
==============================================
riseDT before loop : 2018-11-13 05:30:00
riseDT id()        : 1990840856
attempt to force an independent calcDT created
with the value only of riseDT by using the
.replace() method with no change specified.
calcDT before loop : 2018-11-13 05:30:00
calcDT id()        : 1990671560
It worked before the loop, but issues inside it?
==============================================
Still alright after putting them into a list?
riseDT before loop, in list : 2018-11-13 05:30:00
riseDT id()        :  1990840856
stepS  before loop, in list : 0.5
stepS  id()        :  1990697152
calcDT before loop, in list : 2018-11-13 05:30:00
calcDT id()        :  1990671560
==============================================
==============================================
riseDT inside loop : 2018-11-13 05:30:00
riseDT id()        : 1990840856
calcDT inside loop : 2018-11-13 05:30:00  alright as a var
calcDT id()        : 1990671560
Looks alright here, but put them in a list ...
- - - - - - - - - - - - - - - - - - - - - - - 
Still alright after putting them into a list?
riseDT inside loop, in a list : 2018-11-13 05:30:00
riseDT id()        :  1990840856
stepS  inside loop, in a list : 0.5
stepS  id()        :  1990697152
calcDT inside loop, in a list : 2018-11-13 05:30:00  NG in list?
calcDT id()        :  1990671560
----------------------------------------------
riseDT inside loop : 2018-11-13 05:30:00
riseDT id()        : 1990840856
calcDT inside loop : 2018-11-13 05:30:00.500000  alright as a var
calcDT id()        : 1990671608
Looks alright here, but put them in a list ...
- - - - - - - - - - - - - - - - - - - - - - - 
Still alright after putting them into a list?
riseDT inside loop, in a list : 2018-11-13 05:30:00
riseDT id()        :  1990840856
stepS  inside loop, in a list : 0.5
stepS  id()        :  1990697152
calcDT inside loop, in a list : 2018-11-13 05:30:00  NG in list?
calcDT id()        :  1990671560
----------------------------------------------
riseDT inside loop : 2018-11-13 05:30:00
riseDT id()        : 1990840856
calcDT inside loop : 2018-11-13 05:30:01  alright as a var
calcDT id()        : 1990669160
Looks alright here, but put them in a list ...
- - - - - - - - - - - - - - - - - - - - - - - 
Still alright after putting them into a list?
riseDT inside loop, in a list : 2018-11-13 05:30:00
riseDT id()        :  1990840856
stepS  inside loop, in a list : 0.5
stepS  id()        :  1990697152
calcDT inside loop, in a list : 2018-11-13 05:30:00  NG in list?
calcDT id()        :  1990671560
----------------------------------------------
riseDT inside loop : 2018-11-13 05:30:00
riseDT id()        : 1990840856
calcDT inside loop : 2018-11-13 05:30:01.500000  alright as a var
calcDT id()        : 1990479624
Looks alright here, but put them in a list ...
- - - - - - - - - - - - - - - - - - - - - - - 
Still alright after putting them into a list?
riseDT inside loop, in a list : 2018-11-13 05:30:00
riseDT id()        :  1990840856
stepS  inside loop, in a list : 0.5
stepS  id()        :  1990697152
calcDT inside loop, in a list : 2018-11-13 05:30:00  NG in list?
calcDT id()        :  1990671560
----------------------------------------------

我了解到,与其他一些语言相比,python语言解释器有一些“奇怪的行为”,有些是隐藏的。我正在尝试了解它们,同时也获得了预期的结果。作为示例,此处记录了其他奇怪的行为。

https://github.com/satwikkansal/wtfpython

我没有权威地认可该链接的经验和知识,但是我遇到了其中一些问题。

我已经使用许多成功的项目对简单的python3进行了一年的编程。我遇到了其中一些python怪异之处,并成功地学习了如何解决它们或与它们一起工作。这使我一直感到困惑。

我自由地承认我缺少一些可能非常简单的东西,可能对我眼前的事物变得“视而不见”,因此,我要求寻求帮助以查看使该代码易于阅读的简单解决方案,并且可以按预期工作,即使这需要纠正我的期望。

谢谢。

更新: 这已经得到回答,并以此进行标记。令人尴尬的错误,但在此我以其为例,说明另一组眼睛在花太多时间尝试所有可能的补救措施而又遗漏了简单问题的同时,仔细检查自己的代码的重要性。有时候,人们可能会陷入对问题肯定存在的位置的了解,因此对问题的真正所在视而不见,而且非常简单。

1 个答案:

答案 0 :(得分:0)

简短回答

id()每次吐出相同整数的原因是,您正在索引相同索引 每次

您一直添加到fullPassList而不清除它。在代码中仅访问前三个元素。

当列表随着新calcDT的增长而增长时,对其索引编制的代码将无法跟上。它只是停留在fullPassList[2]上。当然,那里的物体保持不变...

长答案

罪魁祸首

让我们看一下calcDT = riseDT.replace()

之后的代码部分
print('calcDT before loop :', calcDT)
print('calcDT id()        :', id(calcDT))
print('It worked before the loop, but issues inside it?')
print('==============================================')
print('Still alright after putting them into a list?')
fullPassList.append(riseDT)                       # index   [0]   ## OK
fullPassList.append(stepS)                        # index   [1]   ## OK
fullPassList.append(calcDT)                       # index   [2]   ## Yep
print('riseDT before loop, in list :', fullPassList[0])           ## All these are fine.
print('riseDT id()        : ', id(fullPassList[0]))
print('stepS  before loop, in list :', fullPassList[1])
print('stepS  id()        : ', id(fullPassList[1]))
print('calcDT before loop, in list :', fullPassList[2])
print('calcDT id()        : ', id(fullPassList[2]))
print('==============================================')
print('==============================================')

while calcDT <= setDT:    # should show 4 result sets

    print('riseDT inside loop :', riseDT)
    print('riseDT id()        :', id(riseDT))
    print('calcDT inside loop :', calcDT, ' alright as a var')
    print('calcDT id()        :', id(calcDT))
    print('Looks alright here, but put them in a list ...')
    print('- - - - - - - - - - - - - - - - - - - - - - - ')

    # pyephem code start
    #  does stuff but irrelevant to issue
    # pyephem code end

    print('Still alright after putting them into a list?')
    # No.  calcDT goes back to referencing the memory location of riseDT
    # when calcDT is put into a list and then accessed in the list.

然后是关键时刻

    fullPassList.append(riseDT)                       # index   [0] ## Nope
    fullPassList.append(stepS)                        # index   [1] ## Nope
    fullPassList.append(calcDT)                       # index   [2] ## Ditto

这会将日期时间推到第一个循环的索引3、4、5; 6、7、8在第二;等等。因此,

    print('riseDT inside loop, in a list :', fullPassList[0])  ## oops?
    print('riseDT id()        : ', id(fullPassList[0]))
    print('stepS  inside loop, in a list :', fullPassList[1])  ## oops?
    print('stepS  id()        : ', id(fullPassList[1]))
    print('calcDT inside loop, in a list :', fullPassList[2], ' NG in list?')  ## oops!
    print('calcDT id()        : ', id(fullPassList[2]))  ## oops!!!
    print('----------------------------------------------')

该代码反复查询fullPassList[2]。每次给出相同的结果。不是你想要的。 :-)

您去了,已检测到错误。

建议的解决方案

有几种方法可以解决此问题。您只想要 calcDT

list.clear()

fullPassList.clear()放入循环中的某个位置。也许在# pyephem code end之后并在您进行.append()之前?

这将使fullPastList[0]fullPastList[1]fullPastList[2]中正确引用新添加的日期时间。

list[-index]

您仍然可以保留旧的日期时间,并只需为fullPastList[-3]索引倒数第二个元素riseDT,为{{1}索引倒数第二个元素fullPastList[-2],就可以访问新添加的日期时间}},以及stepS的最后一个元素fullPastList[-1]。保持先前的值可能会更方便。

但是您提到calcDTriseDT不会改变...这促使我猜测

选项#3

在while循环中,在代码结尾之前,注释掉两行,然后...

stepS

因此,您只需要将# fullPassList.append(riseDT) ## You already appended these before the loop. # fullPassList.append(stepS) ## Since they'll be constant, it'll be a waste of space ## to append these. fullPassList.append(calcDT) ## You still want to append this since it will change ## on each loop. print('riseDT inside loop, in a list :', fullPassList[0]) ## This is fine, this will print('riseDT id() : ', id(fullPassList[0])) ## still access `riseDT` print('stepS inside loop, in a list :', fullPassList[1]) ## This is also fine. print('stepS id() : ', id(fullPassList[1])) ## Change these to access the LAST element, using list[-1] print('calcDT inside loop, in a list :', fullPassList[-1], ' NG in list?') print('calcDT id() : ', id(fullPassList[-1])) print('----------------------------------------------') 添加到列表中。我敢肯定,您的代码比这要复杂得多。但希望该答案概述了您所面临的头部抓挠和动荡的罪魁祸首。