zoukankan      html  css  js  c++  java
  • 5)协程二(yeild from)

     一:yield from说明

           python从3.3版本开始使用yield from 替代yield 

       yield from 结构会在内部自动捕获 StopIteration 异常。

      这种处理方式与 for 循环处理 StopIteration 异常的方式一样:循环机制使用用户易于理解的方式处理异常。

      对 yield from 结构来说,解释器不仅会捕获 StopIteration 异常,还会把value 属性的值变成 yield from 表达式的值。

      yield from x 表达式对 x 对象所做的第一件事是,调用 iter(x),从中获取迭代器。

      因此, x 可以是任何可迭代的对象可是,如果 yield from 结构唯一的作用是替代产出值的嵌套 for 循环,这个结构很有可能不会添加到 Python 语言中。

      yield from 的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起来,

      这样二者可以直接发送和产出值,还可以直接传入异常,而不用在位于中间的协程中添加大量处理异常的样板代码。

      有了这个结构,协程可以通过以前不可能的方式委托职责。

      PEP 380 使用了一些专门的术语   

       #委派生成器

          包含 yield from <iterable> 表达式的生成器函数。
        #子生成器
          从 yield from 表达式中 <iterable> 部分获取的生成器
      委派生成器在 yield from 表达式处暂停时,调用方可以直接把数据发给子生成器,子生成器再把产出的值发给调用方。

      子生成器返回之后,解释器会抛出 异常,并把返回值附加到异常对象上,此时委派生成器会恢复

      二:示例

        示例:使用 yield from 计算平均值并输出统计报告
        # _*_ coding:utf-8 _*_
        __author__ = "lixiang"
        from collections import namedtuple
        Result = namedtuple('Result', 'count average')
        
        # 子生成器
        def averager():         #1
            total = 0.0
            count = 0
            average = None
            while True:
                term = yield    #2
                if term is None:#3
                    break
                total += term
                count += 1
                average = total/count
            return Result(count, average) #4
        
        # 委派生成器
        def grouper(results, key): #5
            while True:             #6
                results[key] = yield from averager() #7
        
        # 客户端代码,即调用方
        def main(data): #8
            results = {}
            for key, values in data.items():
                group = grouper(results, key)   #9
                next(group) #10
                for value in values:
                    group.send(value)   #11
                    group.send(None) # 重要!#12
            # print(results) # 如果要调试,去掉注释
            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))
        
        data = {
            'girls;kg':
            [40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],
            'girls;m':
            [1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],
            'boys;kg':
            [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
            'boys;m':
            [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
        }
        if __name__ == '__main__':
            main(data)
        
        """
        ❶ 的 averager 协程一样。这里作为子生成器使用。
        ❷ main 函数中的客户代码发送的各个值绑定到这里的 term 变量上。
        ❸ 至关重要的终止条件。如果不这么做,使用 yield from 调用这个协程的生成器会永
        远阻塞。
        ❹ 返回的 Result 会成为 grouper 函数中 yield from 表达式的值。
        ❺ grouper 是委派生成器。
        ❻ 这个循环每次迭代时会新建一个 averager 实例;每个实例都是作为协程使用的生成
        器对象。
        ❼ grouper 发送的每个值都会经由 yield from 处理,通过管道传给 averager 实
        例。 grouper 会在 yield from 表达式处暂停,等待 averager 实例处理客户端发来的
        值。 averager 实例运行完毕后,返回的值绑定到 results[key] 上。 while 循环会不断
        创建 averager 实例,处理更多的值。
        ❽ main 函数是客户端代码,用 PEP 380 定义的术语来说,是“调用方”。这是驱动一切的
        函数。
        ❾ group 是调用 grouper 函数得到的生成器对象,传给 grouper 函数的第一个参数是
        results,用于收集结果;第二个参数是某个键。 group 作为协程使用。
        ❿ 预激 group 协程。
        ⓫ 把各个 value 传给 grouper。传入的值最终到达 averager 函数中 term = yield 那
        一行; grouper 永远不知道传入的值是什么。
        ⓬ 把 None 传入 grouper,导致当前的 averager 实例终止,也让 grouper 继续运行,
        再创建一个 averager 实例,处理下一组值。
  • 相关阅读:
    WCF bindings comparison z
    DevExpress打印功能 z
    使用Topshelf 5步创建Windows 服务 z
    Log4net中的RollingFileAppender z
    Log4Net在Windows服务中不能记录日志 z
    dev 注册方法 z
    async callback z
    多窗体之间方法调用 z
    [JS6] 通过用户事件事件执行脚本
    [JS5] 利用onload执行脚本
  • 原文地址:https://www.cnblogs.com/lixiang1013/p/9392857.html
Copyright © 2011-2022 走看看