我有这个生成器:
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
表达式。
因此,当没有请求下一个值时,生成器将暂停并且无法执行代码来“检测”它没有被请求另一个值。
调用生成器函数时会发生什么:
- 特别generator iterator object被退回。函数体中没有代码被执行。
- 生成器迭代器之外的代码 可能会也可能不会将其用作迭代器。每次需要一个新值时,
generator_object.next()
被称为。 - 当
.next()
方法被调用时,函数体运行,直到遇到yield
表达式。函数体暂停,yield
表达式的结果作为.next()
方法的结果返回。
您可以使用 generator_object.send()
在生成器函数中显式发送消息或引发异常和 generator_object.throw()
方法,但在不遍历生成器对象时不会发送此类消息或异常。
您可以寻找的一件事是当生成器对象关闭时在您的生成器函数中抛出的GeneratorExit
异常;查看generator_object.close()
method :
Raises a
GeneratorExit
at the point where the generator function was paused
当一个生成器对象被垃圾收集(例如,没有任何东西再引用它)时,generator_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
演示:
>>> 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 i in gen():
... break
...
Generator closed early after 1 rounds
这之所以有效,是因为返回的生成器对象仅被 for
循环引用,并且在 for
循环结束时被获取。
关于python - 如何在发电机中检测到它已被外部中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26057722/