__del__
es un finalizador . Se llama cuando un objeto se recolecta como basura, lo que ocurre en algún momento después de que se hayan eliminado todas las referencias al objeto.
En un caso simple, esto podría ser justo después de decir del x
o, si x
es una variable local, después de que finalice la función. En particular, a menos que haya referencias circulares, CPython (la implementación estándar de Python) recolectará basura inmediatamente.
Sin embargo, este es un detalle de implementación de CPython. La única propiedad requerida de la recolección de basura de Python es que ocurre después de que se han eliminado todas las referencias, por lo que es posible que esto no suceda inmediatamente después y que no suceda en absoluto .
Aún más, las variables pueden vivir durante mucho tiempo por muchas razones , por ejemplo, una excepción que se propaga o la introspección del módulo pueden mantener el recuento de referencias de variables mayor que 0. Además, la variable puede ser parte del ciclo de referencias : CPython con la recolección de basura activada se interrumpe más , pero no todos, esos ciclos, e incluso entonces solo periódicamente.
Dado que no tiene garantía de que se ejecute, nunca se debe poner el código con el que debe ejecutarse; en __del__()
cambio, este código pertenece a la finally
cláusula del try
bloque oa un administrador de contexto en una with
declaración. Sin embargo, hay casos de uso válidos para __del__
: por ejemplo, si un objeto hace X
referencia Y
y también mantiene una copia de la Y
referencia en un global cache
( cache['X -> Y'] = Y
), sería de buena educación X.__del__
eliminar también la entrada de la caché.
Si usted sabe que el destructor proporciona (en violación de la directriz anterior) una limpieza necesaria, es posible que desee llamar directamente , ya que no hay nada especial en él como un método: x.__del__()
. Obviamente, debe hacerlo solo si sabe que no le importa que lo llamen dos veces. O, como último recurso, puede redefinir este método utilizando
type(x).__del__ = my_safe_cleanup_method
__exit__
en este contexto? ¿Se ejecuta después o antes__del__
o en conjunto?__del__
posible que los métodos no se ejecuten incluso al finalizar el programa, e incluso cuando se ejecutan al finalizar, escribir un__del__
método que funcione correctamente incluso cuando el intérprete está ocupado autodestruyéndose a su alrededor requiere una codificación más cuidadosa que la que aplican muchos programadores. (La limpieza de CPython generalmente hace que los__del__
métodos se ejecuten en el cierre del intérprete, pero aún hay casos en los que no es suficiente. Los subprocesos de demonio, los globales de nivel C y los objetos__del__
creados en otro__del__
pueden llevar a que los__del__
métodos no se ejecuten).Escribí la respuesta para otra pregunta, aunque esta es una pregunta más precisa.
¿Cómo funcionan los constructores y destructores?
Aquí hay una respuesta ligeramente obstinada.
No lo use
__del__
. Esto no es C ++ ni un lenguaje creado para destructores. El__del__
método realmente debería desaparecer en Python 3.x, aunque estoy seguro de que alguien encontrará un caso de uso que tenga sentido. Si necesita usarlo__del__
, tenga en cuenta las limitaciones básicas según http://docs.python.org/reference/datamodel.html :__del__
se llama cuando el recolector de basura está recolectando los objetos, no cuando pierde la última referencia a un objeto y no cuando ejecutadel object
.__del__
es responsable de llamar a cualquiera__del__
en una superclase, aunque no está claro si esto está en orden de resolución de método (MRO) o simplemente llamando a cada superclase.__del__
medio de que el recolector de basura se rinda en detectar y limpiar cualquier enlace cíclico, como perder la última referencia a una lista enlazada. Puede obtener una lista de los objetos ignorados de gc.garbage. A veces puede usar referencias débiles para evitar el ciclo por completo. Esto se debate de vez en cuando: consulte http://mail.python.org/pipermail/python-ideas/2009-October/006194.html .__del__
función puede hacer trampa, guardar una referencia a un objeto y detener la recolección de basura.__del__
se ignoran.__del__
complementa__new__
mucho más que__init__
. Esto se vuelve confuso. Consulte http://www.algorithm.co.il/blogs/programming/python-gotchas-1- del -is-not-the-opuesto-of- init / para obtener una explicación y trucos.__del__
no es un niño "muy querido" en Python. Notará que la documentación de sys.exit () no especifica si la basura se recolecta antes de salir, y hay muchos problemas extraños. Llamar a los__del__
globales provoca problemas de pedidos extraños, por ejemplo, http://bugs.python.org/issue5099 . ¿Debería__del__
llamar incluso si__init__
falla? Consulte http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 para ver un hilo largo.Pero en la otra mano:
__del__
significa que no te olvides de llamar a una declaración de cierre. Consulte http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/ para obtener un__del__
punto de vista profesional . Por lo general, se trata de liberar ctypes o algún otro recurso especial.Y mi razón personal para que no me guste la
__del__
función.__del__
se convierte en treinta mensajes de confusión.Entonces, encuentre una razón para no usar
__del__
.fuente
__del__
, sino cómo llamar__del__
, su respuesta es interesante.El
__del__
método, se llamará cuando el objeto sea recolectado como basura. Sin embargo, tenga en cuenta que no se garantiza necesariamente que se llame. El siguiente código por sí solo no lo hará necesariamente:La razón es que
del
simplemente reduce el recuento de referencias en uno. Si algo más tiene una referencia al objeto,__del__
no se llamará.Sin
__del__
embargo, hay algunas advertencias sobre el uso . Por lo general, no suelen ser muy útiles. Me parece más bien que desea usar un método cercano o tal vez una declaración with .Consulte la documentación de Python sobre
__del__
métodos .Otra cosa a tener en cuenta: los
__del__
métodos pueden inhibir la recolección de basura si se usan en exceso. En particular, una referencia circular que tiene más de un objeto con un__del__
método no obtendrá la recolección de basura. Esto se debe a que el recolector de basura no sabe a cuál llamar primero. Consulte la documentación sobre el módulo gc para obtener más información.fuente
El
__del__
método (¡tenga en cuenta la ortografía!) Se llama cuando su objeto finalmente se destruye. Técnicamente hablando (en cPython) es cuando no hay más referencias a su objeto, es decir, cuando sale del alcance.Si desea eliminar su objeto y, por lo tanto, llamar al
__del__
método, useque eliminará el objeto (siempre que no haya otras referencias a él).
Te sugiero que escribas una clase pequeña como esta.
E investigar en el intérprete de Python, por ejemplo
Tenga en cuenta que jython y ironpython tienen reglas diferentes en cuanto a exactamente cuándo se elimina y
__del__
se llama al objeto. Sin__del__
embargo, no se considera una buena práctica debido a esto y al hecho de que el objeto y su entorno pueden estar en un estado desconocido cuando se llama. Tampoco está absolutamente garantizado__del__
que se llamará: el intérprete puede salir de varias formas sin eliminar todos los objetos.fuente
use del obj1
parece una mala idea en la que confiar.Como se mencionó anteriormente, la
__del__
funcionalidad es algo poco confiable. En los casos en que pueda parecer útil, considere utilizar los métodos__enter__
y en su__exit__
lugar. Esto le dará un comportamiento similar a lawith open() as f: pass
sintaxis utilizada para acceder a los archivos.__enter__
se llama automáticamente al entrar en el ámbito dewith
, mientras que__exit__
se llama automáticamente al salir. Consulte esta pregunta para obtener más detalles.fuente