我可以这样做:
>>> 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的内容。
答案 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)
除了引用不保存在命名变量中,而是保存在生成器内部。