Что происходит с генератором после возврата значения, продолжает ли он работать
Что проверяют
Понимаете ли разницу между yield и return внутри генератора и знаете ли, куда девается возвращённое значение. Заодно смотрят, помните ли вы, что генератор одноразовый.
Как отвечать
Коротко: yield приостанавливает, return завершает. После yield кадр функции жив, локальные переменные сохранены, генератор ждёт следующего запроса значения. После return, как и после достижения конца тела, генератор закрывается окончательно и переходит в состояние, которое inspect.getgeneratorstate показывает как GEN_CLOSED.
Возвращённое значение не теряется: оно кладётся в атрибут value исключения StopIteration.
def gen():
yield 1
return "итог"
g = gen()
next(g) # 1
try:
next(g)
except StopIteration as e:
e.value # 'итог'Обычный цикл for это значение молча выбрасывает. Забирает его yield from, для которого результатом выражения как раз и становится то, что вернул вложенный генератор; на этом построены сопрограммы старого стиля. Каждый следующий запрос значения у закрытого генератора снова возбуждает StopIteration, уже пустое. Перемотать генератор нельзя: чтобы пройти данные заново, нужен новый вызов функции.
Где спотыкаются
Говорят, что генератор возвращает StopIteration. Он его возбуждает, и это принципиально: значение не приходит как результат, его забирают из атрибута пойманного исключения, а цикл for просто гасит это исключение и завершается.
Второе: пишут return со значением и ждут, что оно придёт последним элементом при переборе. Не придёт. Если значение нужно потребителю, его отдают через yield или получают через yield from.
Третье: возбуждают StopIteration внутри генератора, чаще всего вызовом next() по вложенному итератору без значения по умолчанию. Такое исключение превращается в RuntimeError, а не завершает генератор тихо, как было в старых версиях языка.