Подтвердить что ты не робот

Когда использовать возврат (что-то вывести)?

Долгое время я не знал, что вы не можете поставить return перед оператором yield. Но на самом деле вы можете:

def gen():
    return (yield 42)

который похож на

def gen():
    yield 42
    return

И единственное, что я могу придумать, это прикрепить отправленное значение к StopIteration: pep-0380

return expr в генераторе вызывает остановку StopIteration (expr) при выходе из генератора.

def gen():
    return (yield 42)

g = gen()
print(next(g))  # 42
try:
    g.send('AAAA')
except StopIteration as e:
    print(e.value)  # 'AAAA'

Но это можно сделать и с помощью дополнительной переменной, которая более явная:

def gen():
    a = yield 42
    return a

g = gen()
print(next(g))
try:
    g.send('AAAA')
except StopIteration as e:
    print(e.value)  # 'AAAA'

Итак, кажется, что return (yield xxx) - это просто синтаксический сахар. Я что-то пропустил?

4b9b3361

Ответ 1

Внутри генератора выражения (выход 42) будут давать значение 42, но оно также возвращает значение, которое либо равно None, если вы используете next(generator) или заданное значение, если используете generator.send(value).

Итак, как вы говорите, вы можете использовать промежуточное значение для получения того же поведения, а не потому, что это синтаксический сахар, а потому, что выражения yield буквально возвращают значение, которое вы его отправляете.

Вы также можете сделать что-то вроде

def my_generator():
    return (yield (yield 42) + 10)

Если мы назовем это, используя последовательность вызовов:

g = my_generator()
print(next(g))
try:
    print('first response:', g.send(1))
    print('Second response:', g.send(22))
    print('third response:', g.send(3))
except StopIteration as e:
    print('stopped at', e.value)

Сначала мы получаем результат 42, и генератор по существу приостановлен в состоянии, которое вы могли бы описать как: return (yield <Input will go here> + 10), Если мы тогда назовем g.send(1), получим вывод 11. и теперь генератор находится в состоянии: return <Input will go here>, то отправка g.send(22) приведет к выбросу StopIteration(22) из-за того, как обратная обработка обрабатывается в генераторах. Таким образом, вы никогда не добираетесь до третьего отправления из-за исключения.

Надеюсь, что в этом примере становится более очевидным, как yield работает в генераторах и почему синтаксис return (yield something) не является чем-то особенным или экзотичным и работает точно так, как вы ожидали.

Что касается буквального вопроса, когда вы это сделаете? Хорошо, когда когда-либо вы хотите что-то уступить, а затем позже возвратите StopIteration, эхо-сигнал ввода пользователя, отправленного генератору. Потому что это буквально то, что говорится в коде. Я ожидаю, что такое поведение очень редко требуется.

Ответ 2

yield - это как возврат - он возвращает все, что вы ему рассказываете. Единственное различие заключается в том, что при следующем вызове функции выполнение начинается с последнего вызова в оператор yield.