Pergunta

Estou fazendo algo como um agendador de tarefas usando geradores como coroutinas. No código abaixo, eu preciso executar o print cleanup deterministicamente.

Parece que, pela minha interação, liberar o objeto para o coletor de lixo faz com que o gerenciador de contexto saia. Mas eu sei melhor do que confiar no momento de um GC. É realmente o GC chamando o __exit__ Ou é outro mecanismo?

Como posso forçar estritamente 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
Foi útil?

Solução

Sim, o GC está chamando o __del__ gancho de limpeza do gerador, que por sua vez levanta um GeneratorExit na função do gerador para sair do gerador (ligando generator.close()).

Isso significa o gerente de contexto __exit__ O gancho será chamado sempre que uma função de gerador for limpa da memória.

Você pode fechar manualmente o gerador primeiro, com generator.close():

b.close()

Outras dicas

Você precisa fazer com que o gerador saia. Se a natureza do gerador deve procurar para sempre, você pode usar o Gen.Throw () para aumentar uma exceção no gerador.

Na verdade, eu apenas olhei para a especificação para os geradores e eles têm um método Close () que faz exatamente isso (ele levanta uma exceção generatorexit () dentro do gerador. Então, ligue para gen.close () quando terminar com isso qualquer coisa Qualquer gerente de contexto invocará seu saída métodos. O gerador comerá a exceção para que você não precise envolver a chamada Close () em um bloco de tentativa:

>>> b= bar()
>>> b.next()
setup
'bar'
>>> b.close()
cleanup
>>>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top