一、yield

关于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执行

这样就达到了外界直接与子生成器直接交互的功能。

总结:

  1. 所有new_outer的实例作为调用者把值send过去,都等于直接发送给了子迭代器gen_yield,而子迭代器yield回来的值也登月直接给了调用者。意思就是nwe_outer委托gen_yield工作。
  2. 当new_outer实例调用send方法,就等于gen_yield子迭代器同步调用send方法,把值send到子迭代器内部yield。
  3. 当子迭代器gen_yield内部捕获到StopIteration时,子迭代器内部停止执行,开始执行委托者new_outer.
  4. 委托生成器有一个 throw() 方法可发送任何除了 GeneratorExit 的异常都将被直接发送给子迭代器 。同理,如果这次调用产生了 StopIteration 异常,那么委托生成器 new_outer 将被恢复执行
  5. 如果向委托生成器发送了 GeneratorExit 异常或者调用委托生成器的 close() 方法,那么首先子迭代器 b 的 close() 方法就会被调用(如果有的话)。随后,委托生成器就会引发 GeneratorExit 异常,从而退出
  6. 如果迭代器 gen_yield中有 return value ,那么当 子迭代器 执行 return 返回时,等价于 raise StopIteration(value)(迭代器总是通过引发StopIteration 异常停止),之后该 value 将成为 yield from 表达式值。
  7. 在任意运行时刻,如果迭代器gen_yield抛出了未捕获的异常,那么该异常将会被传播给委托生成器new_outer
带return值的列子
>>> 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的更多相关文章

  1. Python 生成器与迭代器 yield 案例分析

    前几天刚开始看 Python ,后因为项目突然到来,导致Python的学习搁置了几天.然后今天看回Python 发现 Yield 这个忽然想不起是干嘛用的了(所以,好记性不如烂笔头.).然后只能 花点 ...

  2. node 异步回调解决方法之yield

    先看如何使用 使用的npm包为genny,npm 安装genny,使用 node -harmony 文件(-harmony 为使用es6属性启动参数) 启动项目 var genny= require( ...

  3. yield生成器及字符串的格式化

    一.生成器 def ran(): print('Hello world') yield 'F1' print('Hey there!') yield 'F2' print('goodbye') yie ...

  4. Python中的生成器与yield

    对于python中的yield有些疑惑,然后在StackOverflow上看到了一篇回答,所以搬运过来了,英文好的直接看原文吧. 可迭代对象 当你创建一个列表的时候,你可以一个接一个地读取其中的项.一 ...

  5. Python yield函数理解

    Python中的yield函数的作用就相当于一个挂起,是不被写入内存的,相当于一个挂起的状态,用的时候迭代,不用的时候就是一个挂起状态,挂起状态会以生成器的状态表现

  6. ecma6 yield

    function * generator(k){ console.log('begin'); var x = yield k; console.log('x:',x); var y = yield x ...

  7. Python yield与实现

    Python yield与实现  yield的功能类似于return,但是不同之处在于它返回的是生成器. 生成器 生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭 ...

  8. 可惜Java中没有yield return

    项目中一个消息推送需求,推送的用户数几百万,用户清单很简单就是一个txt文件,是由hadoop计算出来的.格式大概如下: uid caller 123456 12345678901 789101 12 ...

  9. 使用yield进行异步流程控制

    现状 目前我们对异步回调的解决方案有这么几种:回调,deferred/promise和事件触发.回调的方式自不必说,需要硬编码调用,而且有可能会出现复杂的嵌套关系,造成"回调黑洞" ...

  10. GetEnumerator();yield

    GetEnumerator()方法的实质实现: 说明:只要一个集合点出GetEnumerator方法,就获得了迭代器属性,就可以用MoveNext和Current来实现foreach的效果,如上图. ...

随机推荐

  1. Python3 socket网络编程(一)

    Socket的定义 套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象.它们允许程序接受并进行连接,如发送和接受数据.为了建 ...

  2. Windows7安装Bitvise开启ssh服务

    Windows7安装Bitvise开启ssh服务 by:铁乐猫 在Liunx和windows10上配置SSH服务是一件很容易的事,毕竟系统己经自带了ssh的服务功能. 不过在windows7上可不容易 ...

  3. C# -- 随机数(Random)的使用

    使用随机数产生一组大乐透号码 1. C#代码 1 Console.WriteLine("===============大乐透===红色球==============="); Lis ...

  4. Servlet(四):转发与重定向、路径问题

    在上次的小案例中用到了转发的技术,今天来仔细聊聊转发和重定向的问题,以及一些小知识的汇总. 一.转发 1.转发的概念 转发主要是将浏览器的请求交给另外一个servlet或jsp来处理,借助reques ...

  5. May 23. 2018 Week 21st Wednesday

    You should love and take care of yourself because after all, it is your own life. 要学会爱自己,照顾自己,毕竟生活是你 ...

  6. MATLAB—求直线或者线段之间的交点坐标

    function CrossPoint( ) %% 求两条直线的交点坐标 x1 = [7.8 8]; y1 = [0.96 0.94]; %line2 x2 = [8.25 8.25]; y2 = [ ...

  7. 平方根的C语言实现(一) —— 浮点数的存储

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7203254.html 作者:窗户 Q ...

  8. 精度 Precision

    柏拉图认为,尽管世间万物是不完美的,但存在一种永恒不变的形式,这个形式是完美的,而生命的意义就是让这个世界尽可能的接近这个完美的形式. 怎么理解这句话,和我们今天讲的精度有什么关系.我们先举一个例子, ...

  9. 51nod 1238 最小公倍数之和 V3

    51nod 1238 最小公倍数之和 V3 求 \[ \sum_{i=1}^N\sum_{j=1}^N lcm(i,j) \] \(N\leq 10^{10}\) 先按照套路推一波反演的式子: \[ ...

  10. jar包内的文件导出的注意点

    1.截取文件名 windows 和linux 通用 String fp[] = filePath.replaceAll("\\\\","/").split(&q ...