Python прикован к форме - PullRequest
       1

Python прикован к форме

0 голосов
/ 07 декабря 2018

Я читал эту статью об асинхронности и ожидании в Python и увидел этот пример кода:

def bottom():
    # Returning the yield lets the value that goes up the call stack to come right back
    # down.
    return (yield 42)

def middle():
    return (yield from bottom())

def top():
    return (yield from middle())

# Get the generator.
gen = top()
value = next(gen)
print(value)  # Prints '42'.
try:
    value = gen.send(value * 2)
except StopIteration as exc:
    value = exc.value
print(value)  # Prints '84'.

Я могу понять, что генераторы цепочки возвращают 42, ноКажется, я не могу разобраться с gen.send(value * 2) и вернуть 84.Я бы подумал, что начальный next(gen) уже исчерпал бы генератор следующим экспериментом?

def bottom():
    # Returning the yield lets the value that goes up the call stack to come right back
    # down.
    return (yield 42)

def middle():
    return (yield from bottom())

def top():
    return (yield from middle())

# Get the generator.
gen = top()
value = next(gen)
print(value)  # Prints '42'.

value = next(gen)
print(value)

Traceback (most recent call last):
  File "a.py", line 16, in <module>
    value = next(gen)
StopIteration

Может кто-нибудь объяснить, пожалуйста?

PS: Не самый продуманный заголовок, кто-то, пожалуйстапомогите исправить это ...

1 Ответ

0 голосов
/ 07 декабря 2018

Как @Steven Rumbalski уже объяснил в комментарии: генератор дает только одно значение - 42. Во втором вызове итератор вызывает StopIteration, который перехватывается except __StopIteration__ as exc:.Таким образом, вы совершенно правы в том, что начальный next(gen) уже исчерпал генератор.То же самое относится и ко второму примеру, но в этом случае вы не получаете исключение StopIteration.Для дальнейшего чтения я приведу цитату из PEP 380 - Синтаксис для делегирования подгенерирующему.

Добавьте новый метод send () для генератора-итераторов, который возобновляет работу генератора.и отправляет значение, которое становится результатом текущего выражения yield.Метод send () возвращает следующее значение, полученное генератором, или увеличивает StopIteration , если генератор выходит без получения другого значения.

из PEP342

Так почему же вы получаете 84 с gen.send(value * 2)?Значение value в этот момент все еще равно 42 от предыдущего вызова value = next(gen).Итак, вы только что вернули те 84, которые хотели отправить в итератор.Почему это так?

Рассмотрим следующие упрощенные примеры, чтобы лучше понять, что означает это определение.Сначала мы приводим только одно значение.Нет возврата.В результате получается пустой StopIteration с атрибутом value None.

def generator():
    yield 1

gen = generator()
value = next(gen)
print(value)  # Prints '1'.
try:
    value = gen.send(3)
except StopIteration as exc:
    value = exc.value
print(value)  # Prints 'None'.

return expr в генераторе, вызывающий StopItered (expr) поднимается при выходе из генератора.

из PEP380

Тогда мы return 2 после того, как генератор не даст большеценности.В этом случае в игру вступает правило из PEP380 .Поскольку 2 было возвращенным значением, атрибут value для StopIteration равен 2.

def generator():
    yield 1
    return 2

gen = generator()
value = next(gen)
print(value)  # Prints '1'.
try:
    value = gen.send(3)
except StopIteration as exc:
    value = exc.value
print(value)  # Prints '2'.

Теперь мы return (yield 1).В соответствии с правилом PEP342 значение 3 в качестве значения gen.send(3) становится результатом текущего выражения доходности.Но поскольку генератор уже исчерпан, возникает исключение StopIteration.Что приводит к 3 как value из поднятого StopIteration.

def generator():
    return (yield 1)

gen = generator()
value = next(gen)
print(value)  # Prints '1'.
try:
     value = gen.send(3)
except StopIteration as exc:
    value = exc.value
print(value)  # Prints '3'.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...