流畅的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 ...
随机推荐
- [PAT] 1144 The Missing Number(20 分)
1144 The Missing Number(20 分) Given N integers, you are supposed to find the smallest positive integ ...
- python 单例模式4中实现方法
python实现单例模式的方法: 1. 使用模块 python的模块在第一次导入时会生成.pyc文件,当第二次导入时就会直接加载.pyc文件,而不会再次执行模块代码. 只需将其单独放在一个模块里,并创 ...
- redis之(六)redis的列表类型的命令
[一]向列表两端添加元素 -->命令:LPUSH key value [value ...] -->向列表的左侧添加元素,返回值表示增加元素后列表的长度 -->命令:RPUSH ke ...
- IO扩展控件(System.IO.Abstractions)
刚看到这个Namespace的时候还以为是.Net Framework里自带的包,结果查了一圈无任何结果.果断上Github搜索,一击即中 https://github.com/tathamoddie ...
- sublime text光标移入移出括号的快捷键设置
使用sublime text每次输入完一个函数或者标签,光标一般都是停留在括号中间,要跳出来要使用左右方向键或者end键 这俩键键区比较远,按起来麻烦,可以自己设置快捷键实现跳出的功能. 原来的快捷键 ...
- rsync数据定时增量备份知识管理服务器数据
为了保证公司知识管理服务器数据的安全性,所以计划每天同步confluence服务器上面数据 一.安装rsync服务端 1.查看是否安装rsync ps -ef | grep rsync 2.添加配置文 ...
- CodeForces 779E Bitwise Formula
位运算,枚举. 按按分开计算,枚举$?$是$0$还是$1$,分别计算出$sum$,然后就可以知道该位需要填$1$还是$0$了. #include<map> #include<set& ...
- 【SQL】ORACLE生成临时表
在日常的SQL查询中,我们需要对要查询的数据进行事先处理,然后再在预先处理好的数据里面进行查询.此时我们就需要用到临时表了,将数据预先处理好放到临时表里面,然后再在临时表里根据我们需要的条件进行查询. ...
- leetcode136 Single Number
题意:数组中每个数字都出现了两次,只有一个出现一次,找出这个数 思路:很明显不能从头到位遍历来找,首先是超时的原因,再次就是这样很没意思·····但是却没想到什么好办法,因为不了解按位异或(XOR). ...
- PHP:根据二维数组中的某个字段进行排序
首先了解下以下两个函数: 1.array_column() 返回输入数组中某个单一列的值. 2.array_multisort() 函数返回排序数组.您可以输入一个或多个数组.函数先对第一个数组进行排 ...