Проблема поведения объекта Python3 DateTime при увеличении и использовании в списке - PullRequest
0 голосов
/ 18 ноября 2018

Я вычисляю орбитальные позиции спутников, используя PyEphem, но проблема, с которой я сталкиваюсь, проявляется отдельно от фактического кода PyEphem, поэтому я упростил пример, исключив любой код pyephem.Однако, ради контекста проекта ... в каждом цикле увеличенный calcDT используется для вычисления деталей прохождения спутника для этого нового calcDT, и все это должно быть сохранено в списке для последующего анализа и построения графика, получения значений, которые яожидал, что я действительно добавился в список.

Здесь задействованы три объекта даты и времени.Время нарастания, установленное время и время расчета, riseDT, setDT и calcDT соответственноПодъемы DT и setDT не должны меняться вообще.Они не.Calc_DT шагает с каждым циклом.Затем calcDT проверяется на равенство с помощью setDT, чтобы увидеть, завершен ли проход.Я использовал .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, а также на нескольких raspberry pi 3B + Raspbian Stretch с локально скомпилированным python 3.7.0 в venv.Результаты, как можно видеть, постоянно нежелательны, здесь, на 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 голосов
/ 18 ноября 2018

Короткий ответ

Причина, по которой id() каждый раз выдает одно и то же целое число, заключается в том, что вы индексируете один и тот же индекс каждый раз .

Вы продолжаете добавлять к fullPassList, не очищая его. В вашем коде доступны только первые три элемента.

По мере того как ваш список растет с новым calcDT, индексирование кода не успевает за ним. Это просто остается на fullPassList[2]. И, конечно, объект там остается прежним ...

Длинный ответ

The Culprit

Давайте посмотрим на часть кода после 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

Это подтолкнет datetime к индексам 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] для stepS и последний элемент fullPastList[-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. Я уверен, что ваш код намного сложнее , чем этот. Но, надеюсь, этот ответ обрисовывает в общих чертах виновника царапин и беспорядков, с которыми вы столкнулись.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...