2017-06-20 28 views
4

我可以這樣做:爲什麼「del x」不會在x.append時更改生成器的結果?

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

'del x'不一定刪除'x'所引用的對象。它只是刪除*名稱'x' *。所以,是的,發電機仍然有一個「a」的參考。 –

+0

所以內容仍然在內存中?那麼內存何時真的被釋放? – ssd

+1

當對象的所有引用都被刪除時,釋放內存。在你的情況下,生成器在名稱「x」被刪除後仍然保存着對象的引用 – inspectorG4dget

回答

6

del不會刪除對象。它刪除名稱。只要有任何引用,對象仍然存在。名稱x和您的生成器y都引用單個對象(列表)。如果你做del x你刪除名稱x,但生成器仍然保存其參考。如果修改x,生成器會看到它,因爲它指的是同一個對象。

2

刪除x只要發電機保持對x的引用,則不起作用。這就像:

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

除了引用不保存在一個命名變量,但內部由生成器。

4

發電機表達式適用於lazy evaluation的概念。

代替存儲整個列表[4, 6, 8],在存儲器中,生成器存儲(x * 2 for x in <some list>)的定義並僅在需要時計算下一個值。

存儲在定義中的東西之一是對用於計算表達式的所有源變量的引用。當在發生器表達式中使用x時,其引用將被存儲並隨後在每個需要的基礎上取消引用。

現在,做

del x 

只會減小該值相關聯的引用計數器。在這兩種情況下,除非刪除其中一個,否則有兩個參考(x以及生成器中的參考)。發電機參考依然存在,這就是爲什麼它可以被評估。

+1

說「存儲所有使用的源變量」是誤導。事實上,只有目標表達式(在這種情況下是'x * 2')被懶惰地評估 - 並且由於它被懶惰地評估,它*將*反映在那裏使用的變量的變化。它只是熱切評估的迭代源(這裏是'x')。例如,如果你做了'g =(a * b for a x)',那麼生成器的值將反映生成器迭代時'b'的值,而不是'b'的值在這個時候創作的。 – BrenBarn

+0

@BrenBarn或許更準確地說源*參考*是存儲的?迭代源被熱切地評估? –

+0

@BrenBarn我認爲你誤解了這句話的意思,但爲了更清晰起見,我編輯了它。 –

相關問題