Поместите yield в try/finally и вызывайте end() в finally. Это обеспечивает очистку при исчерпании или закрытии начатого генератора, но не гарантирует мгновенное закрытие брошенного генератора.
обеспечить вызов end() в функции g()
Поместите yield в try/finally и вызывайте end() в finally. Это обеспечивает очистку при исчерпании или закрытии начатого генератора, но не гарантирует мгновенное закрытие брошенного генератора.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
обеспечить вызов end() в функции g()
не модифицировать функции, кроме g()
def begin(): ...
def end(): ...
def g(): begin() yield 1 yield 2 end()
def f(): a = g() return next(a)
def ff(): for item in g(): ...
Ответ
Поместите yield в try/finally и вызывайте end() в finally. Это обеспечивает очистку при исчерпании или закрытии начатого генератора, но не гарантирует мгновенное закрытие брошенного генератора.
Изменение только g:
def g():
begin()
try:
yield 1
yield 2
finally:
end()
При полном обходе ff блок завершится естественно. В f генератор теряет последнюю локальную ссылку; CPython обычно сразу финализирует его, но язык не гарантирует такой момент сборки во всех реализациях и при циклах ссылок.
Строгая гарантия освобождения при досрочном выходе требует close() или contextlib.closing у потребителя. Если менять потребителей запрещено, эту границу решения нужно прямо обозначить. Незапущенный генератор ещё не вызывал begin.