首页 > 解决方案 > python3 datetime对象在列表中递增和使用时的行为问题

问题描述

我正在使用 PyEphem 计算卫星的轨道位置,但我遇到的问题与实际的 PyEphem 代码不同,因此我简化了示例,不包括任何 pyephem 代码。然而,为了项目上下文......在每个循环中,递增的 calcDT 用于计算该新 calcDT 的卫星通道详细信息,并且全部存储在列表中以供以后分析和绘图,检索我的值预计我实际上已附加到列表中。

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

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

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)

这是运行此代码的结果,显示了问题。我可以在 Toshiba 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 怪事,并成功地学会了如何解决或使用它们。这让我一直很困惑。

我坦率地承认我遗漏了一些可能非常简单的东西,可能对我面前的东西变得“盲目”,所以我寻求帮助以查看一个简单的解决方案,该解决方案将使我的代码非常易于阅读并按预期工作,即使这需要纠正我的期望。

先感谢您。

更新:这已被回答并被标记为这样。令人尴尬的错误,但我把它留在这里作为一个例子,说明在花太多时间尝试所有可能的补救措施之前,另一组眼睛审查一个人的代码的重要性,同时仍然错过了简单的问题。有时人们可能会锁定问题肯定在哪里,从而对问题的实际位置视而不见,而且非常简单。

标签: python-3.xdatetime

解决方案


简答

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

您继续添加fullPassList而不清除它。在您的代码中只访问前三个元素。

随着您的列表随着 new的增长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倒数第二个元素和 的最后一个fullPastList[-2]元素。这可能更方便,因为它保留了以前的值。stepSfullPastList[-1]calcDT

但是你提到了这一点riseDT并且stepS不会改变......这让我推测

选项#3

在您的 while 循环中,就在代码结束之前,注释掉两行并...

# 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('----------------------------------------------')

因此,您需要添加到列表中的只是calcDT. 我确信您的代码比这复杂得多但希望这个答案概述了您所面临的令人头疼和动荡的罪魁祸首。


推荐阅读