2017-02-12 3 views
17

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

def gen(): 
    return (yield 42) 

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

def gen(): 
    yield 42 
    return 

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

возвращение выражение в генератор вызывает остановку StopExteration (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) это просто синтаксический сахар. Я что-то упускаю?

+3

«Но это может быть сделано с использованием дополнительной переменной, которая более ясна» - вы можете сказать это о любом операторе 'return'. 'return x + y' становится' z = x + y; возврат z'.'return foo()' становится 'x = foo(); return x'. Здесь нет ничего конкретного: «return (yield any)» здесь. – user2357112

+0

Что касается аргументов 'StopIteration', вы не должны явно обращаться к ним; это то, как реализуются значения выражения «yield from». Это опубликованная часть API, но обычно это не интересная часть. – user2357112

ответ

4

Внутри генератора выражения (выход 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, эхо-сигнал ввода пользователя, отправленного генератору. Потому что это буквально то, что говорится в коде. Я ожидаю, что такое поведение очень редко требуется.

+0

Интересно. Если я делаю что-то вроде 'x = (yield 42)', а затем 'yield x + 10', используйте' g.send', кажется, что 'x' становится' None', это ожидалось? Почему «х» не становится тем, что я передал «send»? –

+0

@ juanpa.arrivillaga Извините, но вам придется опубликовать код, показывающий, что вы делаете. соединяя то, что вы пишете правильно, дает ожидаемые результаты, поэтому, вероятно, вы не собираете их правильно, так как он не работает для вас. – jVincent

0

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

Смежные вопросы