什么是在生成器内部时触发上下文管理器的__exit__?

时间:2013-11-06 23:32:56

标签: python garbage-collection generator contextmanager

我正在使用生成器作为协程来创建类似任务调度程序的东西。在下面的代码中,我需要确定性地执行print cleanup

从我的交互看来,将对象释放到垃圾收集器会导致上下文管理器退出。但是,我知道最好不要依赖GC的时间。它真的是GC调用__exit__还是另一种机制?

我如何严格强制print 'cleanup'

>>> from contextlib import contextmanager
>>> @contextmanager
... def foo():
...     print 'setup'
...     try:
...         yield
...     finally:
...         print 'cleanup'
... 
>>> def bar():
...     with foo():
...         while True:
...             yield 'bar'
... 
>>> b = bar()
>>> b.next()
setup
'bar'
>>> b = None
cleanup

2 个答案:

答案 0 :(得分:5)

是的,GC正在调用生成器的__del__清理钩子,这会在生成器函数中引发GeneratorExit以退出生成器(通过调用generator.close())。 / p>

这意味着只要从内存中清除生成器函数,就会调用上下文管理器__exit__挂钩。

您可以先使用generator.close()

自行关闭生成器
b.close()

答案 1 :(得分:2)

你必须让发电机退出。如果生成器的性质是永远的,你可以使用gen.throw()在生成器中引发异常。

实际上,我只是查看了生成器的规范,他们有一个方法close()就是这样做了(它在生成器中引发了一个GeneratorExit()异常。所以只要你完成就调用gen.close()任何任何上下文管理器都会调用它们的退出方法。生成器将使用异常,因此您不需要在try块中包含close()调用:

>>> b= bar()
>>> b.next()
setup
'bar'
>>> b.close()
cleanup
>>>