我正在使用生成器作为协程来创建类似任务调度程序的东西。在下面的代码中,我需要确定性地执行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
答案 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
>>>