zltzlt 发表于 2020-4-11 18:48:18

Python 小技巧 075:Python 的 yield from

本帖最后由 zltzlt 于 2020-4-11 18:48 编辑

Python yield from

yield from 是 Python 3.3 新增的语法,这篇帖子将会介绍他的基本用法和高级用法。

一、yield from 的简单用法

它可以替代内层的 for 循环。如果一个生成器需要生成另一个生成器生成的值,有两种方法:

1. 使用 for 循环

    例如:

    >>> def gen():
      for i in range(5):
                yield i

               
>>> list(gen())


2. 直接使用 yield from

    例如:

    >>> def gen():
      yield from range(5)

      
>>> list(gen())


yield from 的原理是,先获取需要 “yield from” 的迭代器,然后遍历这个迭代器,yield 它的每一个值,直到迭代器抛出 StopIteration。

利用 yield from 可以实现 itertools 的 chain 生成器:

>>> def chain(*iterables):
      for i in iterables:
                yield from i


>>> list(chain(range(3), range(25, 30), range(90, 100, 2)))


二、yield from 的高级用法

当然,虽然 yield from 是 yield 的改进版,但是如果仅有上面一点点作用,Python 之父大可不必将它添加进 Python 语法里。

yield from 还改进了 yield 的一些缺点,例如 yield 无法获取生成器 return 的返回值。

我们都知道,在遍历一个生成器并 yield 它的每一个元素时,如果使用 for 语句去迭代生成器,则不会显式地触发 StopIteration 异常,而是自动捕获 StopIteration 异常。

所以如果遇到 return,只会终止迭代,而不会触发异常,因此也就没办法获取 return 的值。

例如:

def gen():
    for i in :
      if i % 2 == 0:    # 遇到第一个偶数强制退出
            return '我被迫退出了'
      yield i


for i in gen():
    print(i)

打印的是 3 5 7 9,迭代到 8 的时候生成器 return 时隐式地触发了 StopIteration 异常,但是 for 自动捕捉了这个异常并且退出了循环。

但是使用 next(generator) 一次一次地迭代就会触发 StopIteration 异常,这时我们就可以捕捉并打印生成器的返回值了:

def gen():
    for i in :
      if i % 2 == 0:    # 遇到第一个偶数强制退出
            return '我被迫退出了'
      yield i


g = gen()
while True:
    try:
      print(next(g))
    except StopIteration as e:
      print("value:", e.value)
      break

执行效果:

3
5
7
9
value: 我被迫退出了

现在我们用 yield from 实现同样的功能:

def gen():
    for i in :
      if i % 2 == 0:# 遇到第一个偶数强制退出
            return '我被迫退出了'
      yield i


def wrap_gen(generator):# 定义一个包装生成器的生成器,它的本质还是生成器
    result = yield from generator# 自动触发 StopIteration 异常,并且将 return 的返回值赋值给 yield from 表达式的结果,即 result
    print("result:", result)


def main():
    for j in wrap_gen(gen()):
      print(j)


if __name__ == '__main__':
    main()

执行结果:

3
5
7
9
result: 我被迫退出了

可以看出 yield from 具有以下的特点:

yield from iterable 结构会在内部自动捕获生成器的 StopIteration 异常。

这种处理方式与 for 循环处理 StopIteration 异常的方式一样。

而且对 yield from 结构来说,解释器不仅会捕获 StopIteration 异常,还会把 return 返回的值或者是 StopIteration 的 value 属性的值变成 yield from 表达式的值,即上面的 result。

_2_ 发表于 2020-4-27 13:20:34

学习了!
话说下一次更新是什么时候???{:10_277:}
@zltzlt

liuzhengyuan 发表于 2020-8-1 15:08:23

催更
页: [1]
查看完整版本: Python 小技巧 075:Python 的 yield from