Короткий ответ
yield приостанавливает выполнение функции и возвращает значение вызывающему коду, сохраняя локальное состояние; StopIteration поднимается автоматически, когда выполнение генератора доходит до конца функции.
Как это работает подробнее
При первом next() код выполняется до первого yield, значение возвращается, а состояние (локальные переменные, точка выполнения) замораживается. Следующий next() продолжает выполнение сразу после yield. Когда функция завершается, генератор поднимает StopIteration.
Пример кода
example-243.py
def one_two():
yield 1
yield 2
return "done" # попадёт в StopIteration.value
g = one_two()
print(next(g)) # 1
print(next(g)) # 2
try:
next(g)
except StopIteration as e:
print(e.value) # "done"Что использовать на практике
- Практика.
for-циклы и конструкции типаlist(),sum()сами перехватываютStopIteration— явно ловить его вручную нужно только при ручной работе сnext(). Значение изreturnвнутри генератора попадает в атрибутvalueобъектаStopIterationи используется редко, в основном при делегировании черезyield from.
Подводные камни
- Риски. Вызывают
next()вручную после исчерпания генератора безtry/except; путаютreturnвнутри генератора с обычнымreturn, думая, что он возвращает значение вызывающему напрямую, как из обычной функции.