Contents
30.4.9. 不要通过throw变换生成器的状态¶
除yield from表达式(参见第33条)与send方法外,生成器还有一项高级功能,就是可以把调用者通过throw方法传来的Exception实例重新抛出。这个throw方法用起来很简单:如果调用了这个方法,那么生成器下次推进时,就不会像平常那样,直接走到下一条yield表达式那里,而是会把通过throw方法传入的异常重新抛出。
下面用代码演示这种效果。
class MyError(Exception):
pass
def my_generator():
yield 1
yield 2
yield 3
it = my_generator()
print(next(it))
print(next(it))
print(it.throw(MyError("test error")))
生成器函数可以用标准的try/except复合语句把yield表达式包裹起来,如果函数上次执行到了这条表达式这里,而这次即将继续执行时,又发现外界通过throw方法给自己注入了异常,那么这个异常就会被try结构捕获下来,如果捕获之后不继续抛异常,那么生成器函数会推进到下一条yield表达式。
#!/usr/bin/env python
# -*- coding:utf8 -*-
class MyError(Exception):
pass
def my_generator():
yield 1
try:
yield 2
except MyError:
print("Got MyError!")
else:
yield 3
yield 4
it = my_generator()
print(next(it))
print(next(it))
print(it.throw(MyError("test error")))
要点:
throw方法可以把异常发送到生成器刚执行过的那条yield表达式那里,让这个异常在生成器下次推进时重新抛出。通过throw方法注入异常,会让代码变得难懂,因为需要用多层嵌套的模板结构来抛出并捕获这种异常。
如果确实遇到了这样的特殊情况,那么应该通过类的__iter__方法实现生成器,并且专门提供一个方法,让调用者通过这个方法来触发这种特殊的状态变换逻辑。