defconsumer(): r = '' whileTrue: n = yield r ifnot n: return print('[CONSUMER] Consuming %s...' % n) r = '200 OK'
defproduce(c): c.send(None) n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) print('[PRODUCER] Consumer return: %s' % r) c.close()
from functools import wraps from inspect import getgeneratorstate
defcoroutine(func): @wraps(func) defprimer(*args,**kwargs):# 把被装饰的生成器函数替换成这里的 primer 函数.调用 primer 函数时,返回预激后的生成器 gen = func(*args,**kwargs) # 调用被装饰的函数,获取生成器对象 next(gen) # 预激生成器 return gen # 返回 return primer
@coroutine defsimple_coro(a): print('-> Started: a =', a) b = yield a print('-> Received: b =', b) c = yield a + b print('-> Received: c =', c)
from inspect import getgeneratorstate defsimple_coro(a): print('-> Started: a =', a) b = yield a print('-> Received: b =', b) c = yield a + b print('-> Received: c =', c)
>>> my_coro = simple_coro(14) >>> next(my_coro) -> Started: a = 14 14 >>> my_coro.send('spam') # 发送数据后,在 a + b 过程中会抛出异常 -> Received: b = spam Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 5, in simple_coro TypeError: unsupported operand type(s) for +: 'int'and'str' >>> my_coro.send(60) # 未处理的异常导致协程终止,再次发送数据,抛出 StopIteration Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> getgeneratorstate(my_coro) # 查看此时协程状态为 GEN_CLOSED 'GEN_CLOSED'
defaverager(): total = 0.0 count = 0 average = None whileTrue: term = yield if term isNone: break# 如果激活协程后,调用方发送 None.则跳出循环,返回 Result 对象 total += term count += 1 average = total/count return Result(count, average)
>>> coro_avg = averager() >>> next(coro_avg) >>> coro_avg.send(10) >>> coro_avg.send(30) >>> coro_avg.send(6.5) >>> try: ... coro_avg.send(None) ... except StopIteration as exc: # 捕获 StopIteration 异常,将其 value 赋值给 result ... result = exc.value ... >>> result Result(count=3, average=15.5)
以上获取带有 yield 关键字表达式的协程的返回值虽然要绕个圈子,但这是 PEP 380 定义的方式.而 yield from 结构会在内部自动捕获 StopIteration 异常.这种处理方式与 for 循环处理 StopIteration 异常的方式一样: 循环机制以用户易于理解的方式处理异常.对 yield from 结构来说,解释器不仅会捕获 StopIteration 异常,还会把异常的 value 属性的值变成 yield from 表达式的值.
yield from 表达式
首先要知道,yield from <expr> 表达式是全新的语言结构,其中 <expr> 为可迭代对象.
yield from 表达式做了什么
yield from <expr> 对 <expr> 可迭代对象所做的第一件事是调用 iter(<expr>),从中获取迭代器.
1 2 3 4 5 6 7 8 9 10 11 12
defgen(): for c in'AB': yield c for i in range(1, 3): yield i
# 子生成器, 带有 yield 表达式的生成器函数 defaverager(): total = 0.0 count = 0 average = None whileTrue: term = yield# main 函数中的客户代码发送的各个值绑定到这里的 term 变量上 if term isNone: # 如果发送数据为 None,则跳出循环,返回 Result 对象 break total += term count += 1 average = total/count return Result(count, average) # 返回 Result 对象