Почему вложенные операторы yield from (делегирование генератора) приводят к завершающему значению `None`?

Возможно ли гнездиться 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

Но я подумал, что было бы более питонно использовать вложенное делегирование (желательно даже yield from x from y или же yield from x for x in y, но это не правильный синтаксис). Почему это не работает, как я ожидаю?

1 ответ

Решение

yield это выражение, оно будет оценивать все, что вы send(value) Это. Проще говоря, если вы ничего не отправите, вы получите None выход, потому что значение yield было бы None,

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

Другие вопросы по тегам