I am using Python 3.8.2 on Windows 10.
I have the following code:
x = range(5)
for i in x:
print(i)
del x
Expected Output:
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
Actual Output:
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
On the first iteration I would expect del x
would delete x
so that on the second iteration it would give me error on the line, for i in x:
.
However, it keeps iterating, printing out 1
, then gives me error on the line, del x
.
It seems like it works the same way with any iterables. I tested with dicts, sets, tuples, and lists.
Am I missing something here?
Can anyone explain what is going on?
The loop isn't actually working with x
; it's working with the return value of iter(x)
, which itself holds a reference to the same object as x
. Deleting x
doesn't affect that reference.
del x
only decrements the reference count of the object referenced by x
, and if that reference count reaches 0, the object is subject to garbage collection. It does not immediately destroy the object.
The first time through the loop, the name x
is still defined. That name is removed, though, by del x
, so on the second iteration, del x
produces the NameError
.
You can think of this for
loop as being roughly equivalent to
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
(roughly, because unlike the name x_iter
in this loop, the iterator used by the for
loop as no Python-visible reference).