Что делает return при использовании выражения yield from?

Я не смог найти никаких примеров возвращаемых значений из yield from выражение Я пробовал этот простой код, но безуспешно:

def return4():
    return 4


def yield_from():
    res = yield from range(4)
    res = yield from return4()


def test_yield_from():
    for x in yield_from():
        print(x)


test_yield_from()

Который производит:

» python test.py 
0
1
2
3
Traceback (most recent call last):
  File "test.py", line 52, in <module>
    test_yield_from()
  File "test.py", line 48, in test_yield_from
    for x in yield_from():
  File "test.py", line 44, in yield_from
    res = yield from return4()
TypeError: 'int' object is not iterable

Но я ожидал:

» python test.py 
0
1
2
3
4

Потому что, как указано в PEP:

Кроме того, когда итератор является другим генератором, субгенератору разрешается выполнять оператор возврата со значением, и это значение становится значением выхода из выражения.

Очевидно, я не получаю это объяснение. Как это return в работе "субгенератора" в отношении yield from?

3 ответа

Генераторы могут возвращать значение, когда они исчерпаны:

def my_gen():
    yield 0
    return "done"

g = my_gen()
next(g)
next(g) # raises StopIteration: "done"

Возвращаемое значение в yield from Заявление будет этим значением. например.

def yield_from():
    res = yield from my_gen()
    assert res == "done"

По умолчанию это значение None, То есть res = yield from range(4) установит res как None,

yield from generator коротка для

for i in generator:
    yield i

ну, это немного сложнее, чем это: https://www.python.org/dev/peps/pep-0380/.

это не будет работать хорошо, если generator = 4, (ваш return4() не генератор. это функция.)

чтобы получить то, что вы хотите, вы просто сделаете это:

def yield_from():
    yield from range(4)
    yield 4

Я публикую рабочий пример для ваших тестов.

Функция return4 теперь является генератором. Для этого в любом месте функции должен присутствовать выход (в Python 3.5 есть новая связанная функция, но сейчас это не важно).

Как вы уже цитировали:

Кроме того, когда итератор является другим генератором, субгенератору разрешается выполнять оператор return со значением, и это значение становится значением выхода из выражения

Резюме: вы получите значение. Вы можете напечатать это, например:

def yield_from():
    # ...
    val = yield from return4()
    print("value:", val)  # prints value: 4

Но вы хотите уступить, а не печатать. Вот полный код:

def return4():
    if False:
        yield None
    return 4

def yield_from():
    yield from range(4)
    yield (yield from return4())

def test_yield_from():
    for x in yield_from():
        print(x)

test_yield_from()
# prints numbers 0 to 4

Вы, наверное, спрашиваете себя, для чего это хорошо. Нет почти никакого преимущества, когда вы получаете только значения от генератора. Но yield from это отличная функция, когда вы отправляете значения в генератор. Попробуйте найти хорошее объяснение сопрограмм Python. Это удивительно

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