流畅的python第十六章协程学习记录
从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数。可是,在协
程中,yield 通常出现在表达式的右边(例如,datum = yield),可以产出值,也可
以不产出——如果 yield 关键字后面没有表达式,那么生成器产出 None。协程可能会从
调用方接收数据,不过调用方把数据提供给协程使用的是 .send(datum) 方法,而不是
next(...) 函数。通常,调用方会把值推送给协程。
yield 关键字甚至还可以不接收或传出数据。不管数据如何流动,yield 都是一种流程控
制工具,使用它可以实现协作式多任务:协程可以把控制器让步给中心调度程序,从而激
活其他的协程。
从根本上把 yield 视作控制流程的方式,这样就好理解协程了。
生成器作为协程使用时的行为和状态
使用装饰器自动预激协程
调用方如何使用生成器对象的 .close() 和 .throw(...) 方法控制协程
协程终止时如何返回值
yield from 新句法的用途和语义
使用案例——使用协程管理仿真系统中的并发活动
协程可以身处四个状态中的一个。当前状态可以使用
inspect.getgeneratorstate(...) 函数确定,该函数会返回下述字符串中的一个。
'GEN_CREATED'
等待开始执行。
'GEN_RUNNING'
解释器正在执行。
'GEN_SUSPENDED'
在 yield 表达式处暂停。
'GEN_CLOSED'
执行结束。
因为 send 方法的参数会成为暂停的 yield 表达式的值,所以,仅当协程处于暂停状态时
才能调用 send 方法,例如 my_coro.send(42)。不过,如果协程还没激活(即,状态是
'GEN_CREATED'),情况就不同了。因此,始终要调用 next(my_coro) 激活协程——也
可以调用 my_coro.send(None),效果一样。
在创建好协程之后,需要调用next激活协程,否则会报错。
最先调用 next(my_coro) 函数这一步通常称为“预激”(prime)协程(即,让协程向前执
行到第一个 yield 表达式,准备好作为活跃的协程使用)。

预激协程的装饰器
由于使用协程之前,必须要激活协程,为了简化协程用法,有时会使用一个预激装饰器
from functools import wraps
def coroutine(func):
"""装饰器:向前执行到第一个`yield`表达式,预激`func`"""
@wraps(func)
def primer(*args,**kwargs): ➊
gen = func(*args,**kwargs) ➋
next(gen) ➌
return gen ➍
return primer
终止协程和异常处理
协程中未处理的异常会向上冒泡,传给 next 函数或 send 方法的调用方(即触发协程的
对象)
终止协程的一种方式:发送某个哨符值,让协程退出。内置的 None 和
Ellipsis 等常量经常用作哨符值。Ellipsis 的优点是,数据流中不太常有这个值。我
还见过有人把 StopIteration 类(类本身,而不是实例,也不抛出)作为哨符值;也就
是说,是像这样使用的:my_coro.send(StopIteration)。
从 Python 2.5 开始,客户代码可以在生成器对象上调用两个方法,显式地把异常发给协
程。
这两个方法是 throw 和 close。
generator.throw(exc_type[, exc_value[, traceback]])
致使生成器在暂停的 yield 表达式处抛出指定的异常。如果生成器处理了抛出的异
常,代码会向前执行到下一个 yield 表达式,而产出的值会成为调用 generator.throw
方法得到的返回值。如果生成器没有处理抛出的异常,异常会向上冒泡,传到调用方的上
下文中。
generator.close()
致使生成器在暂停的 yield 表达式处抛出 GeneratorExit 异常。如果生成器没有处
理这个异常,或者抛出了 StopIteration 异常(通常是指运行到结尾),调用方不会报
错。如果收到 GeneratorExit 异常,生成器一定不能产出值,否则解释器会抛出
RuntimeError 异常。生成器抛出的其他异常会向上冒泡,传给调用方。
如何使用close和throw
class DemoException(Exception):
"""为这次演示定义的异常类型。"""
def demo_exc_handling():
print('-> coroutine started')
while True:
try:
x = yield
except DemoException: ➊
print('*** DemoException handled. Continuing...')
else: ➋
print('-> coroutine received: {!r}'.format(x))
raise RuntimeError('This line should never run.')








获取协程的返回值虽然要绕个圈子,但这是 PEP 380 定义的方式,当我们意识到这一点之
后就说得通了:yield from 结构会在内部自动捕获 StopIteration 异常。这种处理方
式与 for 循环处理 StopIteration 异常的方式一样:循环机制使用用户易于理解的方式
处理异常。对 yield from 结构来说,解释器不仅会捕获 StopIteration 异常,还会把
value 属性的值变成 yield from 表达式的值。可惜,我们无法在控制台中使用交互的方
式测试这种行为,因为在函数外部使用 yield from(以及 yield)会导致句法出错。
使用yield from
for c in 'ab':
yield c
等价于
yield from 'ab'
yield from x 表达式对 x 对象所做的第一件事是,调用 iter(x),从中获取迭代器。因
此,x 可以是任何可迭代的对象。
yield from 的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起
来,这样二者可以直接发送和产出值,还可以直接传入异常,而不用在位于中间的协程中
添加大量处理异常的样板代码。有了这个结构,协程可以通过以前不可能的方式委托职
责。

yield from的意义

流畅的python第十六章协程学习记录的更多相关文章
- 流畅的python第十九章元编程学习记录
在 Python 中,数据的属性和处理数据的方法统称属性(attribute).其实,方法只是可调用的属性.除了这二者之外,我们还可以创建特性(property),在不改变类接口的前提下,使用存取方法 ...
- 流畅的python第十四章可迭代的对象,迭代器和生成器学习记录
在python中,所有集合都可以迭代,在python语言内部,迭代器用于支持 for循环 构建和扩展集合类型 逐行遍历文本文件 列表推导,字典推导和集合推导 元组拆包 调用函数时,使用*拆包实参 本章 ...
- 流畅的python第十五章上下文管理器和else块学习记录
with 语句和上下文管理器for.while 和 try 语句的 else 子句 with 语句会设置一个临时的上下文,交给上下文管理器对象控制,并且负责清理上下文.这么做能避免错误并减少样板代码, ...
- 流畅的python第十二章继承的优缺点学习记录
子类化内置类型的缺点 多重集成和方法解析顺序 tkinter
- 高性能MySQL之【第十五章 备份与恢复】学习记录
我们不打算包括的话题: 安全(访问备份,恢复数据的权限,文件是否需要加密) 备份存储在哪里,包括他们应该离源数据多远,以及如何将数据从源头移动到目的地 保留策略.审计 ...
- 进击的Python【第十六章】:Web前端基础之jQuery
进击的Python[第十六章]:Web前端基础之jQuery 一.什么是 jQuery ? jQuery是一个JavaScript函数库. jQuery是一个轻量级的"写的少,做的多&quo ...
- python 教程 第十六章、 正则表达式
第十六章. 正则表达式 1) 匹配多个表达式 记号 re1|re2 说明 匹配正则表达式re1或re2 举例 foo|bar 匹配 foo, bar 记号 {N} 说明 匹配前面出 ...
- Python爬虫十六式 - 第三式:Requests的用法
Requests: 让 HTTP 服务人类 学习一时爽,一直学习一直爽 Hello,大家好,我是Connor,一个从无到有的技术小白.今天我们继续来说我们的 Python 爬虫,上一次我们说到了 ...
- 《Linux命令行与shell脚本编程大全》 第十六章 学习笔记
第十六章:创建函数 基本的脚本函数 创建函数 1.用function关键字,后面跟函数名 function name { commands } 2.函数名后面跟空圆括号,标明正在定义一个函数 name ...
随机推荐
- 51Nod 1022 石子归并 V2(区间DP+四边形优化)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022 题目大意: N堆石子摆成一个环.现要将石子有次序地合并成 ...
- LeetCode解题报告—— Number of Islands & Bitwise AND of Numbers Range
1. Number of Islands Given a 2d grid map of '1's (land) and '0's (water), count the number of island ...
- 数据结构与算法之--高级排序:shell排序和快速排序
高级排序比简单排序要快的多,简单排序的时间复杂度是O(N^2),希尔(shell)排序大约是O(N*(logN)^2),而快速排序是O(N*logN). 说明:下面以int数组的从小到大排序为例. 希 ...
- section
@RenderSection("Header") @section Header { <div class="view"> @foreach ( ...
- Python基础系列----环境的搭建及简单输入、输出
1.Python 以下信 ...
- python之sqlite3使用详解
Python SQLITE数据库是一款非常小巧的嵌入式开源数据库软件,也就是说没有独立的维护进程,所有的维护都来自于程序本身.它使用一个文件存储整个数据库,操 作十分方便.它的最大优点是使用方便,功能 ...
- Linux命令之useradd
useradd [选项] LOGIN(登录名) useradd –D useradd –D [选项] 创建一个新用户或更新默认新用户信息.useradd和adduser命令相同,adduser是use ...
- mvc4 to mvc5 orEF5 to EF6 ,(升级EF6)
把后台MVC4 自动生成的网站从EF5.0 升级为 EF6.1.3 (6.0以上) 报错 找不到方法:“System.Data.Objects.ObjectContext System.Data.En ...
- 概率dp学习记录
论文参考 汤可因<浅谈一类数学期望问题的解决方法> 反正是很神奇的东西吧..我脑子不好不是很能想得到. bzoj 1415 1415: [Noi2005]聪聪和可可 Time Limit: ...
- python 多继承详解
class A(object): # A must be new-style class def __init__(self): print "enter A" print &qu ...