在生成器中与with语句一起使用是否明智? [英] Is it wise to use with with statements in generators?

查看:70
本文介绍了在生成器中与with语句一起使用是否明智?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下Python代码:

Consider the following Python code:

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

在这种情况下,Python是否保证生成器已正确关闭并因此退出了上下文?

In this case, does Python guarantee that the generator is properly closed and, thus, that the context is exited?

我意识到,在实践中,由于引用计数和生成器的急切破坏,CPython中将是这种情况,但是Python可以保证这种行为吗?我确实注意到它确实在Jython中不起作用,因此应该将其视为错误或允许的行为吗?

I realize that it, in practice, is going to be the case in CPython due to reference counting and eager destruction of the generator, but does Python guarantee this behavior? I do notice that it does indeed not work in Jython, so should that be considered a bug or allowable behavior?

推荐答案

是的,您可以在生成器中使用with语句而不会出现问题. Python将正确处理上下文,因为在收集垃圾时将关闭生成器.

Yes, you can use a with statement in a generator without issue. Python will handle the context correctly, because the generator will be closed when garbage collected.

在生成器中,当生成器被垃圾回收时会引发GeneratorExit异常,因为该生成器将在那时关闭:

In the generator a GeneratorExit exception is raised when the generator is garbage collected, because it'll be closed at that time:

>>> 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没有关闭生成器,我会认为是一个错误.

This is part of PEP 342, where closing a generator raises the exception. Reaping a generator that has no references left should always close that generator, if Jython is not closing the generator I'd consider that a bug.

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

See points 4 and 5 of the Specification Summary:

  1. 为生成器迭代器添加close()方法,该方法在生成器暂停的位置引发GeneratorExit.如果 生成器然后升高StopIteration(通过正常退出,或 由于已被关闭)或GeneratorExit(由于未捕获) 例外),close()返回其调用方.如果发电机 产生一个值,并引发RuntimeError.如果发电机 引发任何其他异常,该异常将传播到调用方. 如果生成器由于以下原因已退出,则close()不执行任何操作 异常或正常退出.

  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.

添加支持以确保在生成器时调用close() 迭代器是垃圾回收的.

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

唯一的警告是,在Jython,IronPython和PyPy中,不保证垃圾收集器在退出解释器之前运行.如果这对您的应用程序很重要,则可以显式关闭生成器:

The only caveat then is that in Jython, IronPython and PyPy the garbage collector is not guaranteed to be run before exiting the interpreter. If this is important to your application you can explicitly close the generator:

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

或显式触发垃圾收集.

这篇关于在生成器中与with语句一起使用是否明智?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆