2017-03-16 30 views
0

在玩發電機時,我發現有趣的事情。當我用yield關鍵字定義一個函數時,從它接收到一個生成器,我也刪除了序列的變量,該序列被饋送到函數中。而* POOF!* - 發生器變空了。這是我的步驟:從功能發生器的奇怪行爲

>>> def foo(list_): 
...  for i in list_: 
...    yield i*2 
... 
>>> val = [1, 2, 3, 4] 
>>> gen = foo(val) 
>>> print(tuple(gen)) 
(2, 4, 6, 8) 
>>> del val 
>>> print(tuple(gen)) 
() 
>>> 

它不應該是不可變的嗎?或者,如果它實際上作爲將其變量的所有值提供給它的函數的對象,給出輸出,爲什麼由於缺少鏈接序列而沒有拋出異常?實際上,這個例子可以解釋爲我迭代了一個空序列,結果for _ in []:塊永遠不會啓動。但是,我不能解釋爲什麼沒有拋出異常:

>>> def foo(list_): 
...  for i in list_: 
...    yield i*2 
... 
>>> val = [1, 2, 3, 4] 
>>> gen = foo(val) 
>>> print(tuple(gen)) 
(2, 4, 6, 8) 
>>> del foo 
>>> print(tuple(gen)) 
() 
>>> 

發電機正在這裏起到類似dict.get()功能?我不明白這一點。

+0

事實上,你做了'德爾val'與您觀察到的發電機行爲無關。如果你沒有'del val',你會看到相同的結果。 – user2357112

回答

4

這與被刪除的對象無關。相反,你用盡了發電機;生成器只能迭代一次。如果您需要第二次迭代,請從生成器函數創建一個新的生成器。你看,但不刪除引用相同的行爲:

>>> def foo(list_): 
...  for i in list_: 
...   yield i*2 
... 
>>> val = [1, 2, 3, 4] 
>>> gen = foo(val) 
>>> list(gen) 
[2, 4, 6, 8] 
>>> list(gen) # gen is now exhausted, so no more elements are produced 
[] 
>>> gen = foo(val) # new generator 
>>> list(gen) 
[2, 4, 6, 8] 

注意del foodel val僅刪除參考的對象。如果還有其他引用,就不會刪除函數或列表對象,例如從函數創建的現有生成器。所以gen = foo(val); del foo, val不會打破gen對象,它仍然可以生產值,而無論是fooval引用現有的,因爲gen本身仍然引用它需要完成:

>>> gen = foo(val) 
>>> del foo, val 
>>> list(gen) # gen still references the list and code objects 
[2, 4, 6, 8] 
+0

好吧,但是在刪除函數和序列之後,當我在我的生成器上使用'itertools.tee()'時會發生什麼? – MaxLunar

+0

@MaxLunar:'tee()'也使用引用。 Python中的所有東西都有。 'del'只刪除名稱,然後減少引用計數。只有當計數變爲0時,實際上纔會刪除一個對象。 –

+0

@MaxLunar:換句話說,你可以使用teed-off生成器對象繼續獲取生成的項目。 –