马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 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())
[0, 1, 2, 3, 4]
2. 直接使用 yield from
例如:
>>> def gen():
yield from range(5)
>>> list(gen())
[0, 1, 2, 3, 4]
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)))
[0, 1, 2, 25, 26, 27, 28, 29, 90, 92, 94, 96, 98]
二、yield from 的高级用法
当然,虽然 yield from 是 yield 的改进版,但是如果仅有上面一点点作用,Python 之父大可不必将它添加进 Python 语法里。
yield from 还改进了 yield 的一些缺点,例如 yield 无法获取生成器 return 的返回值。
我们都知道,在遍历一个生成器并 yield 它的每一个元素时,如果使用 for 语句去迭代生成器,则不会显式地触发 StopIteration 异常,而是自动捕获 StopIteration 异常。
所以如果遇到 return,只会终止迭代,而不会触发异常,因此也就没办法获取 return 的值。
例如:
def gen():
for i in [3, 5, 7, 9, 8, 3, 6]:
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 [3, 5, 7, 9, 8, 3, 6]:
if i % 2 == 0: # 遇到第一个偶数强制退出
return '我被迫退出了'
yield i
g = gen()
while True:
try:
print(next(g))
except StopIteration as e:
print("value:", e.value)
break
执行效果:
现在我们用 yield from 实现同样的功能:
def gen():
for i in [3, 5, 7, 9, 8, 3, 6]:
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()
执行结果:
可以看出 yield from 具有以下的特点:
yield from iterable 结构会在内部自动捕获生成器的 StopIteration 异常。
这种处理方式与 for 循环处理 StopIteration 异常的方式一样。
而且对 yield from 结构来说,解释器不仅会捕获 StopIteration 异常,还会把 return 返回的值或者是 StopIteration 的 value 属性的值变成 yield from 表达式的值,即上面的 result。 |