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

时间:2017-04-13 06:33:25

标签: python python-3.x generator yield yield-from

是否可以嵌套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 # ...

如果我使用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)

产生相同的输出而忽略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,但这不是正确的语法)。为什么它不像我期望的那样工作?

1 个答案:

答案 0 :(得分:7)

yield是一个表达式,它会评估你send(value)的任何内容。简而言之,如果您不发送任何内容,那么您将获得None输出,因为yield的值为None

yield from本身等于None,您正在使用其中两个。在第二个yield from,您将迭代一个列表,该列表使用该列表的项目输入生成器,但您还使用yield from返回该生成器表达式,该表达式返回list和自身在每次迭代时相当于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
  4. 不幸的是,由于表达式的性质,无法摆脱None输出。您最好使用from_iterable

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