为什么嵌套"yield from"语句(生成器委托)会产生终止的"None"值?

Reu*_*ani 5 python yield generator python-3.x yield-from

是否可以嵌套yield from语句?

简单的形式是显而易见的:

def try_yield1():
    x = range(3)
    yield from x
Run Code Online (Sandbox Code Playgroud)

哪个产生:

0
1
2
Run Code Online (Sandbox Code Playgroud)

但是,如果我有嵌套的生成器怎么办?

def try_yield_nested():
   x = [range(3) for _ in range(4)]
    yield from ((yield from y) for y in x)
Run Code Online (Sandbox Code Playgroud)

这会产生:

0
1
2
None # why?
0
1
2
None # ...
0
1
2
None # ...
Run Code Online (Sandbox Code Playgroud)

None如果我使用yield from它(为什么它是嵌套的)它为什么会产生?

我知道我可以这样做:

from itertools import chain

def try_yield_nested_alternative():
    x = [range(3) for _ in range(4)]
    yield from chain.from_iterable(x)
Run Code Online (Sandbox Code Playgroud)

这产生相同的输出而忽略了None(这是我期望的).我也可以写一个简单的循环:

for x in [range(3) for _ in range(3)]:
    yield from x
Run Code Online (Sandbox Code Playgroud)

但是,我认为使用嵌套委托会更加pythonic(最好是偶数yield from x from y或者yield from x for x in y,但这不是正确的语法).为什么它没有像我期望的那样工作?

小智 7

yield是一个表达,它会评估你的send(value)一切.简单地说,如果你把它什么都没有,你会得到一个None输出,因为价值yieldNone.

yield from本身等于None,你正在使用其中两个.在第二个yield from你正在迭代一个列表,它输入生成器与该列表的项目,但你也yield from用来返回该生成器表达式,它返回列表和自身,这相当于None每次迭代,这就是为什么在每个项目迭代范围之后,你得到一个None.

基本上这就是发生的事情:

  1. (yield from y) for y in x 产生值,[0,1,2]
  2. yield from产生前一个值,也yield from来自之前的值None.
  3. 评估为[0,1,2],然后添加一个None到期yield from(yield from y) for y in x.

不幸的是None,由于表达式的性质,没有办法摆脱输出.你最好不要使用from_iterable.

来源解释产量表达; https://docs.python.org/2.5/ref/yieldexpr.html