Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does "del x" not change the result of a generator while x.append does?

I can do this:

>>> x = [2,3,4] 
>>> y = (v * 2 for v in x)
>>> del x                          # x is deleted
>>> print(list(y))                 # y still exists
[4, 6, 8]

This may let me think generator y is independent from list x. But I can also do this:

>>> a = [2, 3, 4]
>>> b = (v * 2 for v in a)
>>> a.append(5)                   # change a
>>> print(list(b))                # b is also changed
[4, 6, 8, 10]

This makes me feel that generator b is still pointing to list a. So I am wondering how generator is actually constructed. Or maybe there is something about how x is deleted in the first case.

like image 410
ssd Avatar asked Dec 13 '22 22:12

ssd


2 Answers

del doesn't delete objects. It deletes names. Objects will still exist as long as there is any reference to them. The name x and your generator y both reference a single object (the list). If you do del x you remove the name x, but the generator still holds its reference. If you modify x, the generator sees it, because it is referring to the same object.

like image 125
BrenBarn Avatar answered Dec 28 '22 05:12

BrenBarn


Generator expressions work on the concept of lazy evaluation.

Instead of storing the entire list [4, 6, 8], in memory, the generator stores a definition for (x * 2 for x in <some list>) and computes the next value only when needed.

One of the things stored in the definition is the reference to all source variables to be used in computing the expression. When x is used in the generator expression, its reference is stored and later dereferenced on a per-need basis.

Now, doing

del x

Will only decrement the reference counter associated with this value. In both cases, there are two references (x as well as the reference in the generator) until you delete one of them. The generator reference still exists, which is why it can be evaluated.

like image 37
cs95 Avatar answered Dec 28 '22 06:12

cs95