yield from
关于yield详细可参考我这篇文章
下面是一个带yield的生成器:
def gen_yield():
while True:
recv = yield
do something with recv
现在我们不单独使用gen_yield这生成器,而是通过另一个携程outer_yield完成必要的验证、设置等再去使用它
def outer_yield():
chiled_gen = gen_yield()
chiled_gen.send(None) #准备上子携程
do something just like setting or you want #在这儿做一些设置或者验证工作
while True:
recv = yield
chiled_gen.send(recv) #把上面接收到的消息,发送到子携程处理
以上可知,yield 只允许协程与外界直接交互而不能使得子协程与外界直接交互。而且,我们这里还没有考虑子协程抛出异常,返回等情况。
yield form 应运而生来解决这个问题:
def gen_yield():
while True:
recv = yield
do something with recv
def new_outer():
do something you want
yield from gen_yield() #1 yield from 后必须跟generator object
no = new_outer()
no.send(None) #2启动生成器
这儿我们可以理解为#1 处yield from 把工作下发(委托)给了gen_yield()子生成器
而当#2出外界开始send值与outer交互时,outer直接通过yield from把值发送给子生成器gen_yield执行
这样就达到了外界直接与子生成器直接交互的功能。
总结:
- 所有new_outer的实例作为调用者把值send过去,都等于直接发送给了子迭代器gen_yield,而子迭代器yield回来的值也登月直接给了调用者。意思就是nwe_outer委托gen_yield工作。
- 当new_outer实例调用send方法,就等于gen_yield子迭代器同步调用send方法,把值send到子迭代器内部yield。
- 当子迭代器gen_yield内部捕获到StopIteration时,子迭代器内部停止执行,开始执行委托者new_outer.
- 委托生成器有一个 throw() 方法可发送任何除了 GeneratorExit 的异常都将被直接发送给子迭代器 。同理,如果这次调用产生了 StopIteration 异常,那么委托生成器 new_outer 将被恢复执行
- 如果向委托生成器发送了 GeneratorExit 异常或者调用委托生成器的 close() 方法,那么首先子迭代器 b 的 close() 方法就会被调用(如果有的话)。随后,委托生成器就会引发 GeneratorExit 异常,从而退出
- 如果迭代器 gen_yield中有 return value ,那么当 子迭代器 执行 return 返回时,等价于 raise StopIteration(value)(迭代器总是通过引发StopIteration 异常停止),之后该 value 将成为 yield from 表达式值。
- 在任意运行时刻,如果迭代器gen_yield抛出了未捕获的异常,那么该异常将会被传播给委托生成器new_outer
>>> def inner_gen():
... sum_all = 0
... while True:
... x = yield
... print('recv : {0}'.format(x))
... if x is None:
... return sum_all
... sum_all = sum_all + x
...
>>> def outer():
... while True:
... sum_all = yield from inner_gen()
... print('sum_all is: {0}'.format(sum_all))
... print('outer 执行完毕')
...
>>> out = outer()
>>> out.send(None) # 准备好协程
>>> for i in range(3):
... out.send(i)
...
recv: 0
recv: 1
recv: 2
>>> out.send(None) # 停止子协程
recv : None
sum_all is: 3
outer 执行完毕
>>> for i in range(5):
... out.send(i)
...
recv: 0
recv: 1
recv: 2
recv: 3
recv: 4
>>> out.send(None)
recv: None
sum_all is: 10
outer 执行完毕
>>> out.throw(TypeError) # TypeError 来自 inner_gen 函数
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in outer
File "<stdin>", line 4, in inner_gen
TypeError
使用 send() 方法发送的值将被直接发送字生成器 inner_gen() 中了,throw() 同理。当子迭代器返回时,return 后的值成为 yield from 表达式的值。
yield from 允许外界与子协程直接交互,这样就允许代码重构:把一部分包含 yield 的代码放到另外的函数,再使用 yield from 调用该迭代器。这样就实现委托工作了
yield from的更多相关文章
- Python 生成器与迭代器 yield 案例分析
前几天刚开始看 Python ,后因为项目突然到来,导致Python的学习搁置了几天.然后今天看回Python 发现 Yield 这个忽然想不起是干嘛用的了(所以,好记性不如烂笔头.).然后只能 花点 ...
- node 异步回调解决方法之yield
先看如何使用 使用的npm包为genny,npm 安装genny,使用 node -harmony 文件(-harmony 为使用es6属性启动参数) 启动项目 var genny= require( ...
- yield生成器及字符串的格式化
一.生成器 def ran(): print('Hello world') yield 'F1' print('Hey there!') yield 'F2' print('goodbye') yie ...
- Python中的生成器与yield
对于python中的yield有些疑惑,然后在StackOverflow上看到了一篇回答,所以搬运过来了,英文好的直接看原文吧. 可迭代对象 当你创建一个列表的时候,你可以一个接一个地读取其中的项.一 ...
- Python yield函数理解
Python中的yield函数的作用就相当于一个挂起,是不被写入内存的,相当于一个挂起的状态,用的时候迭代,不用的时候就是一个挂起状态,挂起状态会以生成器的状态表现
- ecma6 yield
function * generator(k){ console.log('begin'); var x = yield k; console.log('x:',x); var y = yield x ...
- Python yield与实现
Python yield与实现 yield的功能类似于return,但是不同之处在于它返回的是生成器. 生成器 生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭 ...
- 可惜Java中没有yield return
项目中一个消息推送需求,推送的用户数几百万,用户清单很简单就是一个txt文件,是由hadoop计算出来的.格式大概如下: uid caller 123456 12345678901 789101 12 ...
- 使用yield进行异步流程控制
现状 目前我们对异步回调的解决方案有这么几种:回调,deferred/promise和事件触发.回调的方式自不必说,需要硬编码调用,而且有可能会出现复杂的嵌套关系,造成"回调黑洞" ...
- GetEnumerator();yield
GetEnumerator()方法的实质实现: 说明:只要一个集合点出GetEnumerator方法,就获得了迭代器属性,就可以用MoveNext和Current来实现foreach的效果,如上图. ...
随机推荐
- 3d max 动作Take 001改名
问题描述 带动作的Fbx文件导入Unity之后,动作名字为Take 001,如下所示: 在max那边是没有办法改名的,只能在Unity中改名. 方法1 1. 选中动画文件,按Ctrl + D,复制一份 ...
- Windows安装paramiko和PyCharm工程导入
借鉴了CSDN博主Liam_Fang的paramiko安装 原文链接:https://blog.csdn.net/weixin_39912556/article/details/80543829 前提 ...
- C++实现程序单实例运行的两种方式
简介 在我们编写程序的时候,经常会注意到的一个问题就是如何能够让程序只运行一个实例,确保不会让同一个程序多次运行,从而产生诸多相同进程,给我们的带来不便呢?那么常用的有以下四种方法,第一种方法是通过扫 ...
- docker容器持久化卷讲解
docker容器自身存储数据效率比较低,因此我们为了提高磁盘IO的性能等,需要在容器中挂载一个外部存储设备.关于讲解大致如下: Docker中的数据可以存储在类似于虚拟机磁盘的介质中,在Docker中 ...
- 在模态框(Modal)中使用UEditor全屏显示的一个坑
根据这个问题很简单就能查到一些文章明确说明了解决问题的方法,就是如下一段代码: var isModal = false; //判断该dom是否为modal var classes = $(contai ...
- C3P0连接池温习1
一.应用程序直接获取数据库连接的缺点 用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长.假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大 ...
- 自己动手写处理器之第二阶段(1)——可编程逻辑器件与PLD电路设计流程
将陆续上传本人写的新书<自己动手写处理器>(尚未出版),今天是第五篇,我尽量每周四篇 通过上一章的介绍,读者应该知道CPU内部有一些主要的电路,比方:译码电路.运算电路.控 ...
- SpringBoot实战之SpringBoot自动配置原理
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- 在git多分支repo仓库中彻底清除大文件
坑的由来 repo中不小心上传了许多测试生成的data.结果可想而知,原本只有代码的仓库突然间变得无比臃肿(或者是慢慢臃肿),从早期的几十MB,迅速飙升至1G. 到底发生了什么 早些时候我对git的原 ...
- pycharm企业版注册码
pycharm下载最新版 链接:https://pan.baidu.com/s/1gKOCf3PQFc1_2amkMUU1-A 提取码:9pt0 下载企业版: http://www.jetbrains ...