9

我在 python 中有一个协程(增强型生成器),在数据结束后要执行一些代码:

def mycoroutine():
  try:
    while True:
      data = (yield)
      print data
  finally:
    raise ValueError
    print "END"

co = mycoroutine()
co.next()

for i in (1,2,3):
  co.send(i)

ValueError引发异常,但解释器仅打印:

Exception ValueError: ValueError() in <generator object mycoroutine at 0x2b59dfa23d20> ignored

有没有办法在调用者中捕获异常?

4

1 回答 1

14

引发异常finally块在生成器关闭时执行。通过在生成器上下文中引发GeneratorExit异常来关闭生成器。

忽略异常,因为生成器在被删除之前不会关闭(在这种情况下,当 Python 退出时自动关闭);生成器__del__处理程序关闭生成器,从而触发finally:块:

>>> def mycoroutine():
...   try:
...     while True:
...       data = (yield)
...       print data
...   finally:
...     raise ValueError
...     print "END"
... 
>>> co = mycoroutine()
>>> co.next()
>>> co.close()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in mycoroutine
ValueError
>>> co = mycoroutine()
>>> co.next()
>>> del co
Exception ValueError: ValueError() in <generator object mycoroutine at 0x1046a9fa0> ignored

清理期间引发的异常总是被忽略;请参阅object.__del__()文档

警告:由于__del__() 调用方法的环境不稳定,在执行期间发生的异常将被忽略,sys.stderr而是打印警告。

解决方案是在清理生成器时不引发异常,或者通过显式关闭生成器来捕获异常:

>>> co = mycoroutine()
>>> co.next()
>>> try:
...     co.close()
... except ValueError:
...     pass
... 
>>> del co
>>> # No exception was raised
... 

您还可以捕获GeneratorExit异常并在此时执行一些清理:

def mycoroutine():
  try:
    while True:
      data = (yield)
      print data
  except GeneratorExit:
    print "Generator exiting!"

但请注意,除StopIteration或之外的任何异常GeneratorExit都将始终传播;请参阅generator.close()文档

如果生成器函数随后引发StopIteration(通过正常退出,或由于已被关闭)或GeneratorExit(通过未捕获异常),则关闭返回其调用者。如果生成器产生一个值,RuntimeError则引发 a。如果生成器引发任何其他异常,则会将其传播给调用者。

于 2013-09-05T13:01:00.333 回答