Search code examples
pythonpython-3.xloopsreferencedel

Why does the loop iterate after deleting the reference to the iterable?


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?


Solution

  • 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).