博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
yield-from示例
阅读量:7033 次
发布时间:2019-06-28

本文共 2801 字,大约阅读时间需要 9 分钟。

#!/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 异常。

转载于:https://www.cnblogs.com/fmgao-technology/p/9202561.html

你可能感兴趣的文章
underscore.js库的浅析
查看>>
Android 通过软引用实现图片缓存,防止内存溢出
查看>>
EXT.NET常用控件使用
查看>>
C语言两种方式实现矩阵的转置
查看>>
javaee自定义servlet的步骤
查看>>
更进ATM
查看>>
C#和.Net的关系
查看>>
(转载)OpenStreetMap初探(一)——了解OpenStreetMap
查看>>
stm32F10x复习-1
查看>>
嵌入式技术学习路线
查看>>
目前为止最好的关于const的解释
查看>>
20145213《信息安全系统设计》第九周学习总结下篇
查看>>
thinkphp疑难解决4
查看>>
黑盒测试(一)
查看>>
Delphi和C++的语法区别 (关于构造和析构)
查看>>
成为Java GC专家(3)—如何优化Java垃圾回收机制
查看>>
IIS的安装
查看>>
Android下运行c程序
查看>>
基础命令集合
查看>>
Hadoop缺省端口列表
查看>>