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

Why does nesting "yield from" statements (generator delegation) produce terminating `None` value?

是否可以嵌套 yield from 语句?

简单的形式很明显:

def try_yield1():
    x = range(3)
    yield from x

产生:

0
1
2

但是如果我有嵌套的生成器呢?

def try_yield_nested():
   x = [range(3) for _ in range(4)]
    yield from ((yield from y) for y in x)

这会产生:

0
1
2
None # why?
0
1
2
None # ...
0
1
2
None # ...

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

我知道我可以做类似的事情:

from itertools import chain

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

产生相同的输出,但不包括 None(这是我所期望的)。我也可以写一个简单的循环:

for x in [range(3) for _ in range(3)]:
    yield from x

但是,我认为使用嵌套委托会更像 Pythonic(甚至最好是 yield from x from yyield from x for x in y,但这不是正确的语法)。为什么它没有像我预期的那样工作?

yield 是一个表达式,它会计算你 send(value) 的任何值。简单地说,如果你什么都不发送,你会得到一个 None 输出,因为 yield 的值将是 None.

yield from 本身等于 None,而您正在使用其中两个。在第二个 yield from 中,您正在迭代一个列表,该列表使用该列表的项目输入生成器,但您还使用 yield from 到 return 那个生成器表达式,returns 列表及其本身在每次迭代时等效于 None,因此为什么在范围的每次项目迭代后你得到一个 None.

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

  1. (yield from y) for y in x 产生值 [0, 1, 2]
  2. yield from 产生前一个的值,也产生前一个 yield from 的值,即 None.
  3. 正在评估 [0, 1, 2],然后由于 (yield from y) for y in x 中的 yield from 而添加 None

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

解释 yield 表达式的来源; https://docs.python.org/2.5/ref/yieldexpr.html