从生成器函数返回的生成器对象是否保留对函数对象的引用?换句话说,是否可以实现可以执行此操作的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__
的方法。是否有可能,或者一旦创建了发电机,链路是否已经丢失?
答案 0 :(得分: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__
的引用,或任何其他参考链,它将允许它检索存储在函数& #39; s __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