8

我正在使用生成器作为协程来制作类似于任务调度程序的东西。在下面的代码中,我需要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
4

2 回答 2

6

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

这意味着__exit__无论何时从内存中清除生成器函数,都会调用上下文管理器挂钩。

您可以先自己手动关闭生成器,使用generator.close()

b.close()
于 2013-11-06T23:37:25.197 回答
2

您必须使生成器退出。如果生成器的本质是永远查找,您可以使用 gen.throw() 在生成器中引发异常。

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

>>> b= bar()
>>> b.next()
setup
'bar'
>>> b.close()
cleanup
>>>
于 2013-11-06T23:37:33.847 回答