从yield 到yield from再到python协程

 

yield 关键字

复制代码
def fib():     a, b = 0, 1    while 1:        yield b        a, b = b, a+b
复制代码

 

yield 是在:PEP 255 -- Simple Generators 这个pep引入的

yield 只能在函数内部使用,包含yield语句的函数称为生成器函数

当调用生成器函数时,并不会执行函数体中的代码,而是返回一个生成器对象

每次调用生成器对象的next()方法时,才会执行生成器函数中的代码,直到遇到yield 或者return 语句。

如果遇到yield 语句, 怎会挂起函数的运行状态,并将yield 右边的表达式的值返回给next()的调用者, 挂起的时候会保存所有本地状态,包括局部变量,指令指针和内部堆栈信息,这样当下次再次调用next()时, 看起来yield 部分就像是调用了一个外部调用一样,可以接着往下执行

注意:try/ finnally 结构中的try子句中不允许使用yield语句, 问题是因为无法保证生成器被恢复,因此无法保证finally块将被执行

 

yield from 关键字

yield from关键字是在:PEP 380 -- Syntax for Delegating to a Subgenerator 中提出的

用于生成器将其部分操作委托给另外一个生成器,这允许将包含yield的一段代码分解出来并放在另外一个生成器中,此外,允许子生成器返回一个值,这个值可供委派生成器使用

 

上述描述听起来可能还是不是特别清楚,我们先看一下语法:

yield from <expr>

 

yield from expr 表达式中,做的第一件事就是调用iter(expr) 从中获取迭代器,因此expr可以是任何可迭代的对象

通过下面的下例子把yield 和yield from 做对比

复制代码
from collections import namedtuple   Result = namedtuple("Result", "count average")  li = [40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5]  # 子生成器def averager():     total = 0.0     count = 0     average = None     while True:         term = yield        if term is None:             break         total += term         count += 1         average = total/count     return Result(count, average)  # 委派生成器def grouper(result, key):     while True:         result[key] = yield from averager()  # 调用方def main():     results = {}     group = grouper(results, "kg")     next(group)     for value in li:         group.send(value)     group.send(None)   if __name__ == "__main__":     main()
复制代码

yield from的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起来,这样二者可以直接发送和产出值,还可以直接传入异常

yield from 的六个重要意义

关于yield from 六点重要的说明:

  1. 子生成器产出的值都直接传给委派生成器的调用方(即客户端代码)
  2. 使用send()方法发送给委派生成器的值都直接传给子生成器。如果发送的值为None,那么会给委派调用子生成器的__next__()方法。如果发送的值不是None,那么会调用子生成器的send方法,如果调用的方法抛出StopIteration异常,那么委派生成器恢复运行,任何其
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信