#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2018/6/20 9:13
# @File    : yield_from11.py

from collections import namedtuple

Result = namedtuple('Result', 'count average')

# 子生成器
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        # main 函数发送数据到这里
        term = yield
        if term is None:  # 终止条件
            break
        total += term
        count += 1
        average = total / count
    return Result(count, average)  # 返回的Result 会成为grouper函数中yield from表达式的值

# 委派生成器
def grouper(results, key):
    # 这个循环每次都会新建一个averager实例,每个实例都是作为协程使用的生成器对象
    while True:
        # grouper 发送的每个值都会经由yield from 处理,通过管道传给 averager
        # grouper 会在yield from表达式处暂停,等待 averager 实例处理客户端发来的值。
        # averager 实例运行完毕后,返回的值绑定到results[key] 上。
        # while 循环会不断创建 averager 实例,处理更多的值。
        results[key] = yield from averager()

# 调用方
def main(data):
    results = {}
    for key, values in data.items():
        # group 是调用grouper函数得到的生成器对象,传给grouper 函数的第一个参数是results,用于收集结果;第二个是某个键
        group = grouper(results, key)
        next(group)
        for value in values:
            # 把各个value传给grouper 传入的值最终到达averager函数中
            # grouper并不知道传入的是什么,同时grouper实例在yield from处暂停
            group.send(value)
            # 把None传入groupper,传入的值最终到达averager函数中,导致当前实例终止。然后继续创建下一个实例。
            # 如果没有group.send(None),那么averager子生成器永远不会终止,委派生成器也永远不会在此激活,也就不会为result[key]赋值
        group.send(None)
    report(results)

# 输出报告
def report(results):
    for key, result in sorted(results.items()):
        group, unit = key.split(';')
        # print('{:2} {:5} averaging {:.2f}{}'.format(result.count, group, result.average, unit))
        print('{:2} {:5} averaging {:.2f}{}'.format(result.count, group, result.average, unit))
        # print(result, type(result))  # Result(count=6, average=54.0) <class '__main__.Result'>

data = {
    'girls;kg': [40, 41, 42, 43, 44, 54],
    'girls;m': [1.5, 1.6, 1.8, 1.5, 1.45, 1.6],
    'boys;kg': [50, 51, 62, 53, 54, 54],
    'boys;m': [1.6, 1.8, 1.8, 1.7, 1.55, 1.6],
}

if __name__ == '__main__':
    main(data)

'''
    这段代码从一个字典中读取男生和女生的身高和体重。然后把数据传给之前定义的 averager 协程,最后生成一个报告。

执行结果为

6 boys  averaging 54.00kg
6 boys  averaging 1.68m
6 girls averaging 44.00kg
6 girls averaging 1.58m

这断代码展示了yield from 结构最简单的用法。委派生成器相当于管道,所以可以把任意数量的委派生成器连接在一起---一个委派生成器使用yield from 调用一个子生成器,
而那个子生成器本身也是委派生成器,使用yield from调用另一个生成器。最终以一个只是用yield表达式的生成器(或者任意可迭代对象)结束。
'''

yield from 的意义

PEP380 分6点说明了yield from 的行为。

子生成器产出的值都直接传给委派生成器的调用方(客户端代码)

使用send() 方法发给委派生成器的值都直接传给子生成器。如果发送的值是None,那么会调用子生成器的 __next__()方法。如果发送的值不是None,那么会调用子生成器的send()方法。如果调用的方法抛出StopIteration异常,那么委派生成器恢复运行。任何其他异常都会向上冒泡,传给委派生成器。

生成器退出时,生成器(或子生成器)中的return expr 表达式会触发 StopIteration(expr) 异常抛出。

yield from表达式的值是子生成器终止时传给StopIteration异常的第一个参数。

传入委派生成器的异常,除了 GeneratorExit 之外都传给子生成器的throw()方法。如果调用throw()方法时抛出 StopIteration 异常,委派生成器恢复运行。StopIteration之外的异常会向上冒泡。传给委派生成器。

如果把 GeneratorExit 异常传入委派生成器,或者在委派生成器上调用close() 方法,那么在子生成器上调用close() 方法,如果他有的话。如果调用close() 方法导致异常抛出,那么异常会向上冒泡,传给委派生成器;否则,委派生成器抛出 GeneratorExit 异常。

yield-from示例的更多相关文章

  1. python yield 使用示例

    1.yield由于创建迭代器 def deal(): tmp = [] for i in range(20): tmp.append(i) if i % 4 == 0: yield tmp tmp = ...

  2. PHP生成器yield使用示例

    <?php function getLines($file) { $f = fopen($file, 'r'); try { while ($line = fgets($f)) { yield ...

  3. 第十三天python3 生成器yield

    生成器generator 生成器指的是生成器对象,可由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数得到一个生成器对象: 生成器函数 函数体中包含yield语句的函数,返 ...

  4. python基础-迭代器和生成器

    一.递归和迭代 1.递归:(问路示例) 递归算法是一种直接或者间接地调用自身算法的过程.在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解. 2.迭代:简单理 ...

  5. ylbtech-LanguageSamples-Yield

    ylbtech-Microsoft-CSharpSamples:ylbtech-LanguageSamples-Yield 1.A,示例(Sample) 返回顶部 “Yield”示例 本示例演示如何创 ...

  6. Scala入门 【1】

    Scala入门 [1] 转载请注明出处:http://www.cnblogs.com/BYRans/ 1 基础 val定义的为常量,var为变量 val name:Type = ***,变量名后加冒号 ...

  7. python系列之 - 并发编程(进程池,线程池,协程)

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  8. Generator和Coroutine学习

    简单的生产者消费者模型 #!/usr/bin/python2.7 def consumer(): while True: newn = yield print 'Consumer : {}'.form ...

  9. python并发编程之进程池,线程池,协程

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  10. Scala详解

    1       快速入门... 4 1.1             分号... 4 1.2             常变量声明... 4 1.2.1         val常量... 4 1.2.2  ...

随机推荐

  1. Build_Release.bat

    Build_Release.bat @echo off pushd "%~dp0" set tag=Release set PATH="C:\Program Files ...

  2. java环信服务端注册IM代码

    下载环信api代码 https://github.com/easemob/emchat-server-examples 里面包含各种语言版本,我只下载了java版emchat-server-java ...

  3. app支付宝支付java服务端代码

    app支付java服务端生成支付单文档 public String aliPay(String amount,Map<String,Object> body){ //实例化客户端 Alip ...

  4. SSM三大框架整合(Spring+SpringMVC+MyBatis)

    一. 导包 18个必须的包 二.配置Spring MVC的web文件 <?xml version="1.0" encoding="UTF-8"?> ...

  5. 【python】import问题总结

    一.绝对引用 首先总结一下import的各种姿势: 1.import package 读这个包的__init__.py 2.import module 读这个模块全部内容 3.import packa ...

  6. 理解字符串 Boyer-Moore 算法

    作者: 阮一峰 上一篇介绍了 kmp算法 但是,它并不是效率最高的算法,实际采用并不多. 各种文本编辑器的"查找"功能(Ctrl+F),大多采用Boyer-Moore算法. Boy ...

  7. Activity Process Task Application 专题讲解

    Activity Process Task Application 专题讲解 Activity.和进程 为了阅读方便,将文档转成pdf http://files.cnblogs.com/franksu ...

  8. ubuntu android 开始git安装

    ubuntu android 开始git安装   git安装: http://source.android.com/source/initializing.html网站提示到以下网址下载: http: ...

  9. js实现城市二级联动列表

    这个是一个同事写的,我看着有用,就cv下来了. 程序功能主要逻辑是: 1.当一级标签市显示默认状态 '-请选择-'时,二级标签要隐藏 2.一级标签选中城市时,二级标签显示在页面,并列出响应市区 3.当 ...

  10. Ubuntu命令:sudo、shutdown、apt-get、vim

    切换成ROOT用户: Ubuntu中默认不开启root账户,所以root账户是没有密码的, 但是会有一个非root的管理员账户,可以通过sudo来获得root权限,现在就可以用这个账户来设置密码 ** ...