yield 与 yield from

Posted cjj-zyj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了yield 与 yield from相关的知识,希望对你有一定的参考价值。

简而言之yield from 就是把main里的send数据 传入yield处,  send(None)的功能近乎于next(w)

def test1():
      while True:   
            yield from test2()

def test2():
      while True:
            y = yield 
            if y == None:
                break

def main():
      w = test1()
      next(w)  
      for i in range(0, 10):
          w.send(i)
      w.send(None)
main()

 

 

 

三者之间的关系图

技术分享图片

 

 

委派生成器在 yield from 表达式处暂停时,调用方可以直接把数据发给子生成器,子生成器再把产出的值发给调用方。子生成器返回之后,解释器会抛出StopIteration 异常,并把返回值附加到异常对象上,此时委派生成器会恢复。

 

 

grouper 发送的每个值都会经由 yield from 处理,通过管道传给 averager 实例。grouper 会在 yield from 表达式处暂停,等待 averager 实例处理客户端发来的值。averager 实例运行完毕后,返回的值绑定到 results[key] 上。while 循环会不断创建 averager 实例,处理更多的值。

外层 for 循环重新迭代时会新建一个 grouper 实例,然后绑定到 group 变量上。前一个 grouper 实例(以及它创建的尚未终止的 averager 子生成器实例)被垃圾回收程序回收。

from collections import namedtuple

Result = namedtuple(Result, count average)

# 子生成器
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        # main 函数发送数据到这里 
        print("in averager, before yield")
        term = yield
        if term is None: # 终止条件
            break
        total += term
        count += 1
        average = total/count

    print("in averager, return result")
    return Result(count, average) # 返回的Result 会成为grouper函数中yield from表达式的值


# 委派生成器
def grouper(results, key):
     # 这个循环每次都会新建一个averager 实例,每个实例都是作为协程使用的生成器对象
    while True:
        print("in grouper, before yield from averager, key is ", key)
        results[key] = yield from averager()
        print("in grouper, after yield from, key is ", key)


# 调用方
def main(data):
    results = {}
    for key, values in data.items():
        # group 是调用grouper函数得到的生成器对象
        group = grouper(results, key)
        print("
create group: ", group)
        next(group) #预激 group 协程。
        print("pre active group ok")
        for value in values:
            # 把各个value传给grouper 传入的值最终到达averager函数中;
            # grouper并不知道传入的是什么,同时grouper实例在yield from处暂停
            print("send to %r value %f now"%(group, value))
            group.send(value)
        # 把None传入groupper,传入的值最终到达averager函数中,导致当前实例终止。然后继续创建下一个实例。
        # 如果没有group.send(None),那么averager子生成器永远不会终止,委派生成器也永远不会在此激活,也就不会为result[key]赋值
        print("send to %r none"%group)
        group.send(None)
    print("report result: ")
    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, 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)

 


以上是关于yield 与 yield from的主要内容,如果未能解决你的问题,请参考以下文章

60简述 yield和yield from关键字。

yield from语法的高级特性

python yield,yield from,深浅拷贝

24 点游戏算法题的 Python 函数式实现: 学用itertools,yield,yield from 巧刷题

Python 中的协程 yield from

生成器函数_yield_yield from_send