一、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. Mybatis 报错 There is no getter for property named '***' in 'class java.lang.String'

    在mapper.xml中 , 如果单参数是String类型 , 且在sql语句中对参数进行了判断 , 如下 when 中的判断 , 如果出现 if 判断也是一样的.都需要把判断中的参数用 _param ...

  2. qemu 虚拟机

    http://blog.csdn.net/caspiansea/article/details/12986565

  3. HTML做的网页 如何使当前页面跳转到另一页面锚点处

    当前页面a.html另一页面b.html当前页面: <a href="b.html#aaa">跳转到b页面aaa处</a>另一页面:<a name=& ...

  4. c# 行转列动态赋值给layui

    数据库存储格式 期望前端显示样式 以下是代码: (1)控制器: [HttpGet("SocialImportLedgerInfo")] public ResultData GetS ...

  5. Django-rest-framework 接口实现 rest_framework 中有已经定义好的 工具类 mixins generics viewsets

    rest_framework.mixins 请求业务 的 5 种实现 ​ mixin(混合类):不能单独使用,和其它类搭配起来使用(利用了Python支持多继承) rest_framework.mix ...

  6. C#事件の事件聚合器

    事件聚合器用于集中管理事件的订阅(Subscribe)和处理(Handle),要使用事件聚合器,首先要理解:事件(event)本质上是一个类. 传统的+=和-=不足: 1.管理很麻烦:2.不方便扩展. ...

  7. 大学?做码农?做project师?

        近期看到一个知乎里非常热闹的讨论.当中讨论到科研能力与project能力,我有非常多感想. 想说说大学CS方向的一些东西.     我不是计算机专业的,如今大二本科工科在读.     我接触编 ...

  8. 基于位置的服务——百度地图SDK练习

    基于位置的服务所围绕的核心就是要先确定出用户所在的位置.通常有两种技术方式可以实现:一种是通过GPS定位,一种是通过网络定位.Android对这两种定位方式都提供了相应的API支持.但由于众所周知的原 ...

  9. xss攻击(跨站脚本)

    原理跨站脚本(Cross site script,简称xss)是一种“HTML注入”,由于攻击的脚本多数时候是跨域的,所以称之为“跨域脚本”. 我们常常听到“注入”(Injection),如SQL注入 ...

  10. [1] 从零开始 TensorFlow 学习

    计算图的基本概念 TensorFlow 的名字中己经说明了它最重要的两个概念一一Tensor 和 Flow Tensor: 张量(高阶数组,矩阵为二阶张量,向量为一阶张量,标量为零阶张量) Flow: ...