Coroutine 终止协程和异常处理

 1 终止协程和异常处理
 2 
 3     协程中未处理的异常会向上冒泡,传给 next 函数或 send 方法的调用方(即触发协程的对象)
 4     终止协程的一种方式:发送某个哨符值,让协程退出。内置的 None 和
 5     Ellipsis 等常量经常用作哨符值。 Ellipsis 的优点是,数据流中不太常有这个值。有人把 
 6     StopIteration 类(类本身,而不是实例,也不抛出)作为哨符值;也就是说,
 7     是像这样使用的: my_coro.send(StopIteration)。从 Python 2.5 开始,客户代码可以在
 8     生成器对象上调用两个方法,显式地把异常发给协程。这两个方法是 throw 和 close。
 9     
10     generator.throw(exc_type[, exc_value[, traceback]])
11       致使生成器在暂停的 yield 表达式处抛出指定的异常。如果生成器处理了抛出的异
12         常,代码会向前执行到下一个 yield 表达式,而产出的值会成为调用 generator.throw
13         方法得到的返回值。如果生成器没有处理抛出的异常,异常会向上冒泡,传到调用方的上
14         下文中。
15     
16     generator.close()
17        致使生成器在暂停的 yield 表达式处抛出 GeneratorExit 异常。如果生成器没有处
18         理这个异常,或者抛出了 StopIteration 异常(通常是指运行到结尾),调用方不会报
19         错。如果收到 GeneratorExit 异常,生成器一定不能产出值,否则解释器会抛出
20         RuntimeError 异常。生成器抛出的其他异常会向上冒泡,传给调用方。
21 
22 让协程返回值
23 
24     from collections import namedtuple
25     
26     Results = namedtuple('Result', 'count average')
27     
28     def coro_average_return():
29         total = 0.0
30         count = 0
31         average = None
32         while 1:
33             term = yield        #  这一版不产出值
34             if term is None:    #  发送 None 会终止循环,导致协程结束,返回结果。一如既往,生成器对象会抛出 StopIteration 异常。异常对象的 value 属性保存着返回的值。
35                 break
36             total += term
37             count += 1
38             average = total / count
39         return Results(count, average)
40      
41     coro4 = coro_average_return()
42     next(coro4)
43     coro4.send(10)
44     coro4.send(15)
45     coro4.send(3)
46     try:
47         coro4.send(None)
48     except StopIteration as exe:
49         result = exe.value        # return 表达式的值会偷偷传给调用方,赋值给 StopIteration 异常的一个属性。
50                                   # 这样做有点不合常理,但是能保留生成器对象的常规行为——耗尽时抛出 StopIteration 异常。
51     
52     获取协程的返回值虽然要绕个圈子,但这是 PEP 380 定义的方式,当我们意识到这一点之
53     后就说得通了: yield from 结构会在内部自动捕获 StopIteration 异常。这种处理方
54     式与 for 循环处理 StopIteration 异常的方式一样:循环机制通过用户易于理解的方式
55     处理异常。对 yield from 结构来说,解释器不仅会捕获 StopIteration 异常,还会把
56     value 属性的值变成 yield from 表达式的值。但是,我们无法在控制台中使用交互的方
57     式测试这种行为,因为在函数外部使用 yield from(以及 yield)会导致句法出错。
原文地址:https://www.cnblogs.com/zzyzz/p/7874126.html