Python 如何在发电机中检测它是否被外部中断
我有这个发电机:Python 如何在发电机中检测它是否被外部中断,python,exception,generator,Python,Exception,Generator,我有这个发电机: def gen(): rounds = 0 for x in xrange(10): rounds += 1 yield x print 'Generator finished (%d rounds)' % (rounds) 如果我通常称之为: for x in gen(): pass 我得到了预期的结果: Generator finished (10 rounds) 但是如果我中断发电机,我什么也得不到:
def gen():
rounds = 0
for x in xrange(10):
rounds += 1
yield x
print 'Generator finished (%d rounds)' % (rounds)
如果我通常称之为:
for x in gen():
pass
我得到了预期的结果:
Generator finished (10 rounds)
但是如果我中断发电机,我什么也得不到:
for x in gen():
break
我想得到:
Generator interrupted (1 rounds)
是否有可能在发电机内部检测到发电机已从外部中断?是否有任何异常可以捕获以检测此事件?您不能,因为生成器的默认行为将一直被中断。生成器每次生成值时都会持续暂停。 换句话说,您对发电机工作原理的理解是不正确的。发电机上的回路完全不受发电机控制;它的任务就是生成下一个值,该值将取消暂停代码,直到执行下一个
yield
表达式
因此,当没有请求下一个值时,生成器将暂停,无法执行代码“检测”它没有被请求另一个值
调用生成器函数时会发生以下情况:
- 退回一张特价票。不执行函数体中的任何代码
- 生成器迭代器之外的代码可能使用它作为迭代器,也可能不使用它。每次需要新值时,都会调用
- 调用
方法时,函数体将运行,直到遇到.next()
表达式。暂停函数体,并将yield
表达式的结果作为yield
方法的结果返回.next()
GeneratorExit
异常;见:
在生成器功能暂停的点处引发一个GeneratorExit
当生成器对象被垃圾收集时(例如,不再有任何对象引用它),将自动调用generator\u object.close()
方法:
def gen():
rounds = 0
for x in xrange(10):
rounds += 1
try:
yield x
except GeneratorExit:
print 'Generator closed early after %d rounds' % rounds
raise
print 'Generator finished (%d rounds)' % rounds
演示:
这仅仅是因为返回的生成器对象只被
for
循环引用,并且在for
循环结束时被获取。Acontextmanager
允许您提供要在生成器退出时执行的代码
from contextlib import contextmanager
rounds = 0
@contextmanager
def on_generator_exit():
try:
yield
finally:
global rounds
print 'Generator finished (%d rounds)' % (rounds)
def gen():
with on_generator_exit():
global rounds
rounds = 0
for x in xrange(10):
rounds += 1
yield x
for x in gen():
break
输出:
Generator finished (1 rounds)
我怀疑是否有
例外情况
。所发生的一切是,只在一次调用之后,函数就停止被调用。因为这样的控制永远不会返回到函数来执行打印
。不,这里没有例外-您只是停止了对它的循环。您可以在外部处理它,方法是保留对生成器的引用,并确保next(gen)
引发StopIteration
,但无法从内部判断-生成器只是等待再次调用或垃圾回收。这不是您要求的,但您可以将生成器包装到上下文管理器中,使用\uuuuuuuuuuuuuuuuu
——类似于:我认为GeneratorExit
对于我正在寻找的东西来说已经足够好了。我想,如果我有一个对生成器的引用,它将不会像预期的那样工作,但是对于简单的情况,只要在它上循环,就会始终产生预期的结果。@jeckyll2hide:考虑到生成器关闭时依赖于Python实现。CPython使用引用计数,生成器对象立即被捕获,但在Jython或IronPython中,在对象不再被引用和垃圾收集清除之间可能存在明显的延迟。
Generator finished (1 rounds)