yield from
yield x
中,x
是一个普通对象,例如3或者[1, 2, 3]
,
yield from x
中,x
是一个iterator,例如下面的代码
来自what's the difference between yield from and yield in python 3.3.2+:
In [1]: def iterable1():
...: yield 1
...: yield 2
...:
...: def iterable2():
...: yield from iterable1()
...: yield 3
...:
In [2]: iter = iterable2()
In [3]: next(iter)
Out[3]: 1
In [4]: next(iter)
Out[4]: 2
In [5]: next(iter)
Out[5]: 3
In [6]: next(iter)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-6-5c05586d40e8> in <module>()
----> 1 next(iter)
StopIteration:
用PEP 380中的术语,iterable2()
是generator,iterable1()
是subgenerator,
iterable2
通过使用yield from
实现对iterable1
的“代理”,
这样上层iterator的代码就可以分散在几个subitorator中,
然后在上层iterator中,用yield from
将这些subitorators组合起来。
再比如下面这个函数,更是直接判断x
是不是iterator,如果是用yield from
,
否则用yield
:
def flatten(sequence):
"""flatten a multi level list or something
>>> list(flatten([1, [2], 3]))
[1, 2, 3]
>>> list(flatten([1, [2], [3, [4]]]))
[1, 2, 3, 4]
"""
for element in sequence:
if hasattr(element, '__iter__'):
yield from flatten(element)
else:
yield element
yield from
的另一个常用方法是后面跟一个range
对象,例如:
>>> 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]
这种用法中的yield from x
等价于for item in x: yield item
(来自PEP 380)。
coroutine
使用coroutine可以在一个线程中同时执行多项任务,在多个函数中切换任务和发送消息。 例如下面的代码来自python generator “send” function purpose?:
def coroutine():
for i in range(1, 5):
print("From generator {}".format((yield i)))
c = coroutine()
c.send(None)
try:
while True:
print("From user {}".format(c.send(1)))
except StopIteration: pass
输出:
From generator 1
From user 2
From generator 1
From user 3
From generator 1
From user 4
From generator 1
接收方通过yield i
拿到发送方发来的值(即send()
的参数1),
发送方则通过c.send(1)
拿到了接收方的当前状态(yield i
中的i
值),
这样就实现了二者间的双向数据传递,
且双方可以在任何时候停下来让对方工作,等待对方处理到一定阶段时把执行权还给自己,
这样就在一个线程里实现了多个任务同时进行的效果。
另一个使用协程实现“生产-消费者模型”的例子可以参考理解python coroutine.