Почему l oop повторяется после удаления ссылки на повторяемое? - PullRequest
1 голос
/ 02 апреля 2020

Я использую Python 3.8.2 для Windows 10.
У меня есть следующий код:

x = range(5)

for i in x:
    print(i)
    del x

Ожидаемый вывод:

0
Traceback (most recent call last):
  File "C:\Users\Students\test.py", line 3, in <module>
    for i in x:
NameError: name 'x' is not defined

Фактический вывод :

0
1
Traceback (most recent call last):
  File "C:\Users\Students\test.py", line 5, in <module>
    del x
NameError: name 'x' is not defined

На первой итерации я ожидал, что del x удалит x, так что на второй итерации это выдаст мне ошибку в строке, for i in x:.
Однако, это продолжает повторять, печатая 1, затем выдает ошибку в строке, del x.
Кажется, что он работает так же, как и любые итерируемые. Я тестировал с помощью диктов, наборов, кортежей и списков.

Я что-то здесь упускаю?
Может кто-нибудь объяснить, что происходит?

1 Ответ

4 голосов
/ 02 апреля 2020

l oop на самом деле не работает с x; он работает с возвращаемым значением iter(x), которое само содержит ссылку на тот же объект, что и x. Удаление x не влияет на эту ссылку.

del x только уменьшает счетчик ссылок объекта, на который ссылается x, и если этот счетчик ссылок достигает 0, объект подвергается сборке мусора. Он не сразу уничтожает объект.

первый первый раз через l oop, имя x все еще определено. Это имя удаляется, однако, del x, поэтому на секунде итерации del x создает NameError.


Вы можете подумать об этом for l oop как приблизительно эквивалентный

x_iter = iter(x)
while True:
    try:
        i = next(x_iter)
    except StopIteration:
        del x_iter  # Clean up the namespace before exiting the loop
        break
    print(i)
    del x

(примерно, потому что в отличие от имени x_iter в этом l oop, итератор, используемый for l oop как нет Python -видимая ссылка).

...