python中的yield from有那么难懂么?一.什么是yield from yield from 是一个在Pyth
一.什么是yield from
yield from
是一个在Python中用于简化协程中生成器委托的语法结构。它允许一个协程将一部分工作委托给另一个生成器,然后等待生成器完成并收集其结果,从而减少了协程中的代码复杂性。
二.yield from的简单实现
yield
是每次惰性返回
一个值,其实从名字中就能看出,yield from
是yield
的升级改进版本,如果将yield
理解成“返回”,那么yield from
就是“从什么(生成器)里面返回”,这就构成了yield from
的一般语法,即:
# yield from 的用法很简单 EXPR是一个可迭代对象 generator
result = yield from EXPR
demo:
def sub_generator():
yield 1
yield 2
yield 3
def main_generator():
yield 'A'
yield from sub_generator() # 委托给子生成器
yield from [11, 12, 13]
yield from (21, 22, 23)
yield from range(31, 34)
yield 'B'
for item in main_generator():
print(item)
总结:
生成器 、元组、 列表、
range()
函数产生的序列等可迭代对象”返回另外一个生成器。而
yield
只是返回一个元素。从这个层面来说,有下面的等价关系:yield from iterable
本质上等于for item in iterable: yield item
。
三.yield from的高级应用
1.针对yiled无法获取生成器return的返回值
在使用yield
生成器的时候,如果使用for
语句去迭代生成器,则不会显式的出发StopIteration
异常,而是自动捕获StopIteration
异常,所以如果遇到return
,只是会终止迭代,而不会触发异常,故而也就没办法获取return
的值。如下:
def test_generator():
for i in range(5):
if i == 2:
return "我被迫中断了"
yield i
def main(g):
try:
for i in g: # 不会显式触发异常,故而无法获取到return的值
print(i)
except StopIteration as e:
print(e.value)
g = test_generator()
main(g)
从上面的例子可以看出,for 迭代语句不会显式触发异常,故而无法获取到return
的值,迭代到2
的时候遇到return
语句,隐式的触发了StopIteration
异常,就终止迭代了,但是在程序中不会显示出来。
def test_generator():
for i in range(5):
if i == 2:
return "我被迫中断了"
yield i
def main2(g):
try:
print(next(g)) # 每次迭代一个值,则会显式出发StopIteration
print(next(g))
print(next(g))
print(next(g))
print(next(g))
except StopIteration as e:
print(e.value) # 获取返回的值
g = test_generator()
main2(g)
现在我们使用yield from
来完成上面的同样的功能:
def test_generator():
for i in range(5):
if i == 2:
return "我被迫中断了"
yield i
def wrap_test_generator(g):
result = yield from g
print(result)
def main(g):
for j in g:
print(j)
g = test_generator()
g = wrap_test_generator(g)
main(g)
从上面的比较可以看出,
yield from
具有以下几个特点:“调用方——>生成器函数(协程函数)”;
“调用方——>生成器包装函数——>生成器函数(协程函数)”;
return
返回的值或者是StopIteration
的value
属性的值变成yield from
表达式的值,即上面的result
。
2.yield from实现的数据传输通道
yield
涉及到“调用方与生成器两者”的交互,生成器通过next()
的调用将值返回给调用者,而调用者通过send()
方法向生成器发送数据;
委派生成器:包含yield from
表达式的生成器函数;即上面的wrap_my_generator
生成器函数
子生成器:从yield from
表达式中 部分获取的生成器;即上面的test_generator
生成器函数
调用方:调用委派生成器的客户端代码;即上面的main生成器函数
委派生成器在yield from
表达式处暂停时,调用方可以直接把数据发给子生成器,子生成器再把产出的值发给调用方。子生成器返回之后,解释器会抛出StopIteration
异常,并把返回值附加到异常对象上,此时委派生成器会恢复。
总结:
yield from
主要设计用来向子生成器委派操作任务,但yield from
可以向任意的可迭代对象委派操作;委派生成器(
group
)相当于管道,所以可以把任意数量的委派生成器连接在一起---一个委派生成器使用yield from
调用一个子生成器,而那个子生成器本身也是委派生成器,使用yield from
调用另一个生成器。
def sub_generator():
received = yield 'sub_generator says hello'
yield f'sub_generator received: {received}'
def main_generator():
response = yield from sub_generator()
yield f'main_generator received: {response}'
gen = main_generator()
print(next(gen)) # 输出 'sub_generator says hello'
print(gen.send('Hi from main_generator')) # 输出 'sub_generator received: Hi from main_generator'
yield from
可以建立双向通信,使调用生成器和委托生成器可以相互传递值。
上述示例中,main_generator
发送消息给 sub_generator
,然后 sub_generator
将回应传回给 main_generator
。
转载自:https://juejin.cn/post/7408037561236504587