Dol*_*000 5 python generator with-statement contextmanager
考虑以下 Python 代码:
def values():
with somecontext():
yield 1
yield 2
for v in values():
print(v)
break
Run Code Online (Sandbox Code Playgroud)
在这种情况下,Python 是否保证生成器已正确关闭,从而退出上下文?
我意识到在实践中,由于引用计数和生成器的急切破坏,在 CPython 中会出现这种情况,但是 Python 是否保证这种行为?我确实注意到它在 Jython 中确实不起作用,所以这应该被视为错误还是允许的行为?
with是的,您可以在生成器中使用语句而不会出现问题。Python 将正确处理上下文,因为生成器将在垃圾收集时关闭。
在生成器中,GeneratorExit当生成器被垃圾收集时,会引发异常,因为那时它将被关闭:
>>> from contextlib import contextmanager
>>> @contextmanager
... def somecontext():
... print 'Entering'
... try:
... yield None
... finally:
... print 'Exiting'
...
>>> def values():
... with somecontext():
... yield 1
... yield 2
...
>>> next(values())
Entering
Exiting
1
Run Code Online (Sandbox Code Playgroud)
这是PEP 342的一部分,其中关闭生成器会引发异常。收获没有留下引用的生成器应该始终关闭该生成器,如果 Jython 没有关闭生成器,我会认为这是一个错误。
请参阅规范摘要的第 4 点和第 5 点:
close()为生成器迭代器添加一个方法,该方法GeneratorExit在生成器暂停的地方引发。如果生成器随后引发StopIteration(通过正常退出,或由于已经关闭)或GeneratorExit(通过不捕获异常),close()则返回到其调用者。如果生成器产生一个值,则 aRuntimeError被提升。如果生成器引发任何其他异常,则会将其传播给调用者。close()如果生成器由于异常或正常退出而已经退出,则不执行任何操作。添加支持以确保
close()在生成器迭代器被垃圾收集时调用。
唯一需要注意的是,在 Jython、IronPython 和 PyPy 中,垃圾收集器不保证在退出解释器之前运行。如果这对您的应用程序很重要,您可以显式关闭生成器:
gen = values()
next(gen)
gen.close()
Run Code Online (Sandbox Code Playgroud)
或显式触发垃圾收集。