Когда запускается __exit__ контекста __exit__, когда внутри генератора?

StackOverflow https://stackoverflow.com/questions/19825106

Вопрос

Я делаю что -то вроде планировщика задач, используя генераторы в качестве коратиков. В приведенном ниже коде мне нужно выполнить print cleanup детерминированно.

Из моего взаимодействия кажется, что освобождение объекта в сборщик мусора заставляет менеджера контекста выходить. Но я знаю лучше, чем полагаться на время GC. Это действительно тот GC, который называет __exit__ Или это другой механизм?

Как я могу строго принудиться print 'cleanup'?

>>> from contextlib import contextmanager
>>> @contextmanager
... def foo():
...     print 'setup'
...     try:
...         yield
...     finally:
...         print 'cleanup'
... 
>>> def bar():
...     with foo():
...         while True:
...             yield 'bar'
... 
>>> b = bar()
>>> b.next()
setup
'bar'
>>> b = None
cleanup
Это было полезно?

Решение

Да, GC звонит __del__ Очистка крюка генератора, который, в свою очередь, поднимает GeneratorExit В функции генератора выйти из генератора (позвонив generator.close()).

Это означает контекст -менеджер __exit__ Крюк будет вызван всякий раз, когда функция генератора очищается по памяти.

Вы можете сначала закрепить генератор самостоятельно, с generator.close():

b.close()

Другие советы

Вы должны привести к выходу генератора. Если природа генератора будет выглядеть вечно, вы можете использовать Gen.Throw (), чтобы поднять исключение в генераторе.

На самом деле, я только что посмотрел на спецификацию для генераторов, и у них есть метод Close (), который делает именно это (он поднимает исключение generatorexit () внутри генератора. Поэтому просто позвоните Gen.close (), когда вы закончите с ним Любые менеджеры контекста будут вызывать свои выход методы Генератор будет съесть исключение, поэтому вам не нужно обернуть звонок Close () в блоке Try:

>>> b= bar()
>>> b.next()
setup
'bar'
>>> b.close()
cleanup
>>>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top