本文参考了:
How the heck does async/await work in Python 3.5?
PEP 380: Syntax for Delegating to a Subgenerator
yield 和 yield from
先让我们来学习或者回顾一下 yield
和 yieldfrom
的用法。如果你很自信自己完成理解了,可以跳到下一部分。
Python3.3提出了一种新的语法: yieldfrom
。
yield from iterator
本质上也就相当于:
for x in iterator:
yield x
下面的这个例子中,两个 yieldfrom
加起来,就组合得到了一个大的 iterable
(例子来源于官网3.3 release):
>>> def g(x):
... yield from range(x, 0, -1)
... yield from range(x)
...
>>> list(g(5))
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
理解 yieldfrom
对于接下来的部分至关重要。想要完全理解 yieldfrom
,还是来看看官方给的例子:
def accumulate():
tally = 0
while 1:
next = yield
if next is None:
return tally
tally += next
def gather_tallies(tallies):
while 1:
tally = yield from accumulate()
tallies.append(tally)
tallies = []
acc = gather_tallies(tallies)
next(acc) # Ensure the accumulator is ready to accept values
for i in range(4):
acc.send(i)
acc.send(None) # Finish the first tally
for i in range(5):
acc.send(i)
acc.send(None) # Finish the second tally
print(tallies)
我还专门为此录制了一段视频,你可以配合文字一起看,或者你也可以打开 pycharm 以及任何调试工具,自己调试一下。 点击原文可查看视频。
来一起 break down:
从 acc=gather_tallies(tallies)
这一行开始,由于 gather_tallies
函数中有一个 yield,所以不会 while1
立即执行(你从视频中可以看到,acc 是一个 generator 类型)。
next(acc)
:
next()会运行到下一个 yield,或者报StopIteration错误。
next(acc)
进入到函数体gathertallies,gathertallies中有一个 yieldfromaccumulate()
,next(acc)不会在这一处停,而是进入到『subgenerator』accumulate里面,然后在 next=yield
处,遇到了 yield
,然后暂停函数,返回。
for i in range(4):
acc.send(i)