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

2024-09-29 23:27:22 发布

您现在位置:Python中文网/ 问答频道 /正文

考虑以下Python代码:

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

在这种情况下,Python是否保证生成器正确关闭,从而退出上下文?在

我意识到,实际上,由于引用计数和对生成器的迫切破坏,CPython中会出现这种情况,但是Python是否保证这种行为?我应该注意到这是一个允许的行为吗?在


Tags: 代码infordefwith情况cpython计数
2条回答

是的,您可以在生成器中使用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没有关闭生成器,我会认为这是一个bug。在

见规范概要第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和pypyy中,不能保证垃圾收集器在退出解释器之前运行。如果这对应用程序很重要,可以显式关闭生成器:

^{pr2}$

或显式触发垃圾回收。在

如果您的重点是安全性,则可以始终将生成器包装在contextlib.closing中-这似乎是最直接的解决方案:

from contextlib import closing

with closing(gen_values()) as values:
    for value in values:
        ...

事实上,如果是我,我会把函数写成

^{pr2}$

确保任何用户都必须将其放入with中才能使用它。在

相关问题 更多 >

    热门问题