为什么" del x" x.append不会改变生成器的结果吗?

时间:2017-06-20 18:15:41

标签: python garbage-collection generator

我可以这样做:

>>> 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]

这可能让我觉得生成器y独立于列表x。但我也可以这样做:

>>> 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]

这让我觉得发电机b仍然指向列表a。所以我想知道如何实际构建发电机。或者也许在第一种情况下有关于如何删除x的内容。

3 个答案:

答案 0 :(得分:6)

del不会删除对象。它删除名称。只要有对象,对象仍然存在。名称x和您的生成器y都引用单个对象(列表)。如果您执行del x,则删除名称x,但生成器仍保留其引用。如果修改x,生成器会看到它,因为它指的是同一个对象。

答案 1 :(得分:4)

生成器表达式适用于lazy evaluation的概念。

生成器不是将整个列表[4, 6, 8]存储在内存中,而是存储(x * 2 for x in <some list>)的定义,并仅在需要时计算下一个值。

定义中存储的一件事是对计算表达式时使用的所有源变量的引用。在生成器表达式中使用x时,将存储其引用,然后根据需要解除引用。

现在,做

del x

仅递减与此值关联的引用计数器。在这两种情况下,有两个引用(x以及生成器中的引用),直到您删除其中一个引用。生成器引用仍然存在,这就是它可以被评估的原因。

答案 2 :(得分:2)

只要生成器保留对x的引用,删除x就不起作用。这就像:

x = [2,3,4] 
y=x
del x
print(y)

除了引用不保存在命名变量中,而是保存在生成​​器内部。