2016-12-24 81 views
3

生成器函數返回的生成器對象是否持有對函數對象的引用?換句話說,是有可能實現magic_fn這可以這樣做:發電機是否知道發電機功能?

>>> def gen(): 
...  yield 1 
...  yield 2 
...  
>>> gen.attr = 'potato' 
>>> g = gen() 
>>> del gen 
>>> next(g) 
1 
>>> magic_fn(g, 'attr') 
'potato' 

該發電機具有一個代碼對象(g.gi_code),幀(g.gi_frame)和名稱(g.__name__)的引用。該代碼對象甚至具有與gen.__code__相同的內存地址。

但是,假設它還沒有被垃圾收集,我找不到方法來訪問gen.__dict__。這是可能的,還是鏈接已經失去了一旦發電機創建?

回答

3

生成器迭代器不引用生成器函數。您可以通過保持一個弱引用的函數,使用weakref.ref看到:

>>> import weakref 
>>> def gen(): 
...  yield 1 
... 
>>> ref = weakref.ref(gen) 
>>> gen_iter = gen() 
>>> del gen 
>>> ref() is None 
True 

不同於一般的引用,一個weakref.ref不耽誤什麼它是指集合。如果所指對象(gen)仍然存在,則ref()將爲gen。如果收集到的指示物,ref()None。正如你所看到的那樣,weakref被清除了,如果gen_iter仍然有對gen的引用,這將不會發生。

同樣,你也可以說,發電機迭代器不保留對功能的__dict__,或其他任何引用鏈,將讓它檢索儲存在該函數的__dict__項目的引用:

>>> class Dummy(object): 
...  pass 
... 
>>> def gen(): 
...  yield 1 
... 
>>> gen.attr = Dummy() 
>>> ref = weakref.ref(gen.attr) 
>>> gen_iter = gen() 
>>> del gen 
>>> ref() is None 
True 
+0

謝謝,我也能夠看到它通過在'Dummy'上執行一個'__del__'來獲得,它打印出'再見'。你能否添加更多關於'weakref.ref'這個用法的解釋和它的工作原理? – wim

+0

@wim:添加了一些弱引用的解釋。 – user2357112