Как @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'.