python - 在生成器中使用 with 语句是否明智?

标签 python generator with-statement contextmanager

考虑以下 Python 代码:

def values():
    with somecontext():
        yield 1
        yield 2
for v in values():
    print(v)
    break

在这种情况下,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

这是 PEP 342 的一部分,其中关闭生成器会引发异常。收割一个没有引用的生成器应该总是关闭那个生成器,如果 Jython 没有关闭生成器我会认为这是一个错误。

请参阅规范摘要的第 4 点和第 5 点:

  1. Add a close() method for generator-iterators, which raises GeneratorExit at the point where the generator was paused. If the generator then raises StopIteration (by exiting normally, or due to already being closed) or GeneratorExit (by not catching the exception), close() returns to its caller. If the generator yields a value, a RuntimeError is raised. If the generator raises any other exception, it is propagated to the caller. close() does nothing if the generator has already exited due to an exception or normal exit.

  2. Add support to ensure that close() is called when a generator iterator is garbage-collected.

唯一需要注意的是,在 Jython、IronPython 和 PyPy 中,不能保证垃圾收集器在退出解释器之前运行。如果这对您的应用程序很重要,您可以明确关闭生成器:

gen = values()
next(gen)
gen.close()

或显式触发垃圾回收。

关于python - 在生成器中使用 with 语句是否明智?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29040534/

相关文章:

python - Python字典中最大值的贪心算法

javascript - 使用 yield/generators 理解代码流

python - open 如何处理上下文管理?

python - 使用 xml.dom.minidom 从 Mysql XML 转储中提取数据

python - django forms.CharField 如何生成所需的输入?

python - 在 Tkinter 中单击按钮时显示 .jpg 图像?

mysql - 在 windows7 的 yii2 中安装 mongodb 失败

node.js - node.js 中的花哨名称生成器

python - 没有 "with"关键字的 "as"语句的含义

delphi - 重构 "with" block 的工具