__del__
é um finalizador . É chamado quando um objeto é coletado como lixo, o que acontece em algum ponto depois que todas as referências ao objeto foram excluídas.
Em um caso simples, isso poderia ser logo após você dizer del x
ou, se x
for uma variável local, após o término da função. Em particular, a menos que haja referências circulares, o CPython (a implementação padrão do Python) fará a coleta de lixo imediatamente.
No entanto, este é um detalhe de implementação do CPython. A única propriedade necessária da coleta de lixo do Python é que ela acontece depois que todas as referências foram excluídas, então isso pode não acontecer necessariamente logo depois e pode nem acontecer .
Ainda mais, as variáveis podem viver por muito tempo por muitos motivos , por exemplo, uma exceção de propagação ou introspecção de módulo pode manter a contagem de referência de variável maior que 0. Além disso, a variável pode ser uma parte do ciclo de referências - CPython com coleta de lixo ativada quebras na maioria , mas não todos, esses ciclos, e mesmo assim, apenas periodicamente.
Já que você não tem garantia de que será executado, nunca se deve colocar o código que você precisa para ser executado __del__()
- em vez disso, esse código pertence à finally
cláusula do try
bloco ou a um gerenciador de contexto em uma with
instrução. No entanto, existem casos de uso válidos para __del__
: por exemplo, se um objeto faz X
referência Y
e também mantém uma cópia de Y
referência em um global cache
( cache['X -> Y'] = Y
), seria educado X.__del__
também excluir a entrada do cache.
Se você sabe que o destruidor fornece (em violação da diretriz acima) a limpeza necessária, você pode querer chamá-lo diretamente , uma vez que não há nada de especial sobre ele como um método: x.__del__()
. Obviamente, você só deve fazer isso se souber que não se importa em ser chamado duas vezes. Ou, como último recurso, você pode redefinir esse método usando
type(x).__del__ = my_safe_cleanup_method
__exit__
neste contexto? É executado depois, antes__del__
ou junto?__del__
métodos podem não ser executados mesmo no encerramento do programa e, mesmo quando são executados no encerramento, escrever um__del__
método que funcione corretamente mesmo quando o interpretador está ocupado se autodestruindo ao seu redor requer uma codificação mais cuidadosa do que muitos programadores aplicam. (A limpeza do CPython geralmente obtém__del__
métodos para serem executados no desligamento do interpretador, mas ainda há casos em que não é suficiente. Threads daemon, globais de nível C e objetos__del__
criados em outro__del__
podem fazer com que os__del__
métodos não sejam executados.)Escrevi a resposta para outra pergunta, embora esta seja uma pergunta mais precisa para ela.
Como funcionam os construtores e destruidores?
Aqui está uma resposta ligeiramente opinativa.
Não use
__del__
. Isso não é C ++ ou uma linguagem construída para destruidores. O__del__
método realmente deveria desaparecer no Python 3.x, embora eu tenha certeza que alguém encontrará um caso de uso que faça sentido. Se precisar usar__del__
, esteja ciente das limitações básicas por http://docs.python.org/reference/datamodel.html :__del__
é chamado quando o coletor de lixo está coletando os objetos, não quando você perde a última referência a um objeto e não quando você executadel object
.__del__
é responsável por chamar qualquer__del__
um em uma superclasse, embora não esteja claro se isso está na ordem de resolução de método (MRO) ou apenas chamando cada superclasse.__del__
significa que o coletor de lixo desiste de detectar e limpar quaisquer links cíclicos, como perder a última referência para uma lista vinculada. Você pode obter uma lista dos objetos ignorados em gc.garbage. Às vezes, você pode usar referências fracas para evitar o ciclo completamente. Isso é debatido de vez em quando: consulte http://mail.python.org/pipermail/python-ideas/2009-October/006194.html .__del__
função pode trapacear, salvando uma referência a um objeto e interrompendo a coleta de lixo.__del__
são ignoradas.__del__
complementa__new__
muito mais do que__init__
. Isso fica confuso. Veja http://www.algorithm.co.il/blogs/programming/python-gotchas-1- del -is-not-the-oposta-of- init / para uma explicação e dicas.__del__
não é uma criança "amada" em Python. Você notará que a documentação sys.exit () não especifica se o lixo é coletado antes de sair, e há muitos problemas estranhos. Chamar o__del__
on globals causa problemas de ordem estranhos, por exemplo, http://bugs.python.org/issue5099 . Deve ser__del__
chamado mesmo se__init__
falhar? Consulte http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 para uma longa conversa.Mas por outro lado:
__del__
significa que você não se esquece de chamar uma instrução de fechamento. Consulte http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/ para um__del__
ponto de vista profissional . Geralmente, trata-se de liberar ctypes ou algum outro recurso especial.E meu motivo pessoal para não gostar da
__del__
função.__del__
fala, isso se transforma em trinta mensagens de confusão.Portanto, encontre um motivo para não usar
__del__
.fonte
__del__
, mas como ligar__del__
, sua resposta é interessante.O
__del__
método, ele será chamado quando o objeto for coletado como lixo. Observe que não é necessariamente garantido que ele seja chamado. O código a seguir por si só não fará isso necessariamente:A razão é que
del
apenas diminui a contagem de referência em um. Se algo mais tiver uma referência ao objeto,__del__
não será chamado.No
__del__
entanto, existem algumas advertências para usar . Geralmente, eles geralmente simplesmente não são muito úteis. Parece-me mais que você deseja usar um método de fechamento ou talvez uma instrução with .Consulte a documentação
__del__
do python sobre métodos .Outra coisa a ser observada: os
__del__
métodos podem inibir a coleta de lixo se usados em excesso. Em particular, uma referência circular que tem mais de um objeto com um__del__
método não será coletada como lixo. Isso ocorre porque o coletor de lixo não sabe qual chamar primeiro. Veja a documentação do módulo gc para mais informações.fonte
O
__del__
método (observe a ortografia!) É chamado quando o objeto é finalmente destruído. Tecnicamente falando (em cPython) é quando não há mais referências ao seu objeto, ou seja, quando ele sai do escopo.Se você deseja deletar seu objeto e assim chamar o
__del__
método, useque excluirá o objeto (desde que não haja nenhuma outra referência a ele).
Eu sugiro que você escreva uma pequena classe como esta
E investigue no interpretador python, por exemplo
Observe que jython e ironpython têm regras diferentes sobre exatamente quando o objeto é excluído e
__del__
chamado. Não é considerado uma boa prática usar,__del__
porém, por causa disso e do fato de que o objeto e seu ambiente podem estar em um estado desconhecido quando ele é chamado. Também não há garantia absoluta de__del__
que será chamado - o intérprete pode sair de várias maneiras sem excluir todos os objetos.fonte
use del obj1
parece uma má ideia confiar.Conforme mencionado anteriormente, a
__del__
funcionalidade não é confiável. Nos casos em que pode parecer útil, considere usar os métodos__enter__
e__exit__
. Isso dará um comportamento semelhante aowith open() as f: pass
sintaxe usada para acessar arquivos.__enter__
é chamado automaticamente ao entrar no escopo dewith
, enquanto__exit__
é chamado automaticamente ao sair dele. Veja esta pergunta para mais detalhes.fonte