在python 3.3里,generator新增了一个语法 yield from
这个yield from的作用是什么?看下面两段对比的代码:
def zero_to_nine():
for i in range(10):
yield i
def wrap_generator():
for i in zero_to_nine():
yield i
print(list(zero_to_nine()))
print(list(wrap_generator()))
可以看到一个问题,如果一个函数内部调用了一个generator,它自身如果还希望是以generator的形式返回值的话,就需要用for循环重新yield一次。
使用yield from可以简化这个委托给子generator的过程
def zero_to_nine():
for i in range(10):
yield i
def wrap_generator():
yield from zero_to_nine()
print(list(zero_to_nine()))
print(list(wrap_generator()))
如果只是这么一点写法上的区别的话,也就不劳烦BDFL添加新的语法了。我们可以看一下wrap_generator的bytecode
0 LOAD_GLOBAL 0 (zero_to_nine)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 GET_ITER
7 LOAD_CONST 0 (None)
10 YIELD_FROM
11 POP_TOP
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
可见YIELD FROM是由cPython内部支持的,其实现原理上就避免了栈进栈出的消耗,直接由最内层的frame返回(yield)值。
另外YIELD FROM可以实现外部直接向最内层的generator传递值,比如
def i_yield_whatever_input_is():
input = None
while True:
input = yield input
def wrap_generator():
yield from i_yield_whatever_input_is()
gen = wrap_generator()
print(gen.send(None))
print(gen.send(1))
print(gen.send(2))
print(gen.send(3))
这段代码的输出是
None
1
2
3
这样send传值的方式,在用for循环重新yield的模式下是无法实现的。这也就是tulip必须使用yield from,而不能使用yield的原因。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。