捕获Python中生成器调用者抛出的异常

Sno*_*all 4 python generator coroutine python-2.7

我正试图捕获生成器调用者抛出的异常:

class MyException(Exception):
    pass

def gen():
    for i in range(3):
        try:
            yield i
        except MyException:
            print 'handled exception'

for i in gen():
    print i
    raise MyException
Run Code Online (Sandbox Code Playgroud)

这输出

$ python x.py
0
Traceback (most recent call last):
  File "x.py", line 14, in <module>
    raise MyException
__main__.MyException
Run Code Online (Sandbox Code Playgroud)

当我打算输出它时

$ python x.py
0
handled exception
1
handled exception
2
handled exception
Run Code Online (Sandbox Code Playgroud)

回想起来,我认为这是因为调用者与生成器的堆栈不同,因此异常不会冒泡到生成器.那是对的吗?是否有其他方法来捕获调用者中引发的异常?

旁白:我可以使用generator.throw()使其工作,但这需要修改调用者:

def gen():
    for i in range(3):
        try:
            yield i
        except MyException:
            print 'handled exception'
            yield

import sys
g = gen()
for i in g:
    try:
        print i
        raise MyException
    except:
        g.throw(*sys.exc_info())
Run Code Online (Sandbox Code Playgroud)

use*_*ica 5

你可能会想到,当执行yield器在生成器中命中时,生成器执行for循环体,有点像Ruby函数yield和块.这不是Python中的工作方式.

当执行命中时yield,生成器的堆栈帧被挂起并从堆栈中移除,并且控制返回到(隐式)调用生成器next方法的代码.然后该代码进入循环体.在引发异常时,生成器的堆栈帧不在堆栈中,并且异常在发生气泡时不会通过生成器.

生成器无法响应此异常.