Я не понимаю, как и когда менеджер контекста в незавершенном генераторе закрывается. Рассмотрим следующий менеджер контекста и функцию:
from contextlib import contextmanager
@contextmanager
def ctx():
print('enter ctx')
yield
print('exit ctx')
def gen_nums(n):
with ctx():
yield from range(n)
Моя первая интуиция заключалась в том, что если я позвоню gen_nums
, но не использую генератор полностью, ctx
никогда не закроется, что было довольно актуально. Например:
for i, j in zip(range(5), gen_nums(10)):
print(f'{i}, {j}')
Здесь exit ctx
- это , а не , напечатанный в конце. На мой взгляд, это означало, что если бы у меня был файловый контекст в генераторе, он был бы оставлен открытым; однако затем я понял, что выполнение того же с файлами фактически закроет файл должным образом. После некоторых тестов я узнал, что если я сделал:
from contextlib import contextmanager
@contextmanager
def ctx():
print('enter ctx')
try:
yield
finally:
print('exit ctx')
Теперь exit ctx
был напечатан в конце. Поэтому я предполагаю, что какое-то исключение будет вызвано в какой-то момент, но я не знаю, где, когда и как (я пытался напечатать исключение с помощью except BaseException as e
, но это не сработало). Кажется, это происходит, когда генератор удаляется, потому что если я сделаю:
g = gen_nums(10)
for i, j in zip(range(5), g):
print(f'{i}, {j}')
del g
Тогда exit ctx
происходит только после del g
. Однако я хотел бы лучше понять, что здесь происходит и кто что запускает.