__del__
est un finaliseur . Il est appelé lorsqu'un objet est garbage collection, ce qui se produit à un moment donné après que toutes les références à l'objet ont été supprimées.
Dans un cas simple, cela peut être juste après que vous ayez dit del x
ou, s'il x
s'agit d'une variable locale, après la fin de la fonction. En particulier, à moins qu'il y ait des références circulaires, CPython (l'implémentation standard de Python) effectuera immédiatement une récupération de place.
Cependant, il s'agit d'un détail d'implémentation de CPython. La seule propriété requise du garbage collection Python est que cela se produit après que toutes les références ont été supprimées, donc cela peut ne pas nécessairement se produire juste après et peut ne pas se produire du tout .
De plus, les variables peuvent vivre longtemps pour de nombreuses raisons , par exemple, une exception de propagation ou une introspection de module peut maintenir le nombre de références de variables supérieur à 0. En outre, la variable peut faire partie du cycle de références - CPython avec garbage collection activé interrompt le plus , mais pas tous, de tels cycles, et même alors seulement périodiquement.
Puisque vous n'avez aucune garantie qu'il soit exécuté, il ne faut jamais mettre le code dans lequel vous devez être exécuté __del__()
- à la place, ce code appartient à la finally
clause du try
bloc ou à un gestionnaire de contexte dans une with
instruction. Cependant, il existe des cas d'utilisation valides pour __del__
: par exemple, si un objet X
référence Y
et conserve également une copie de Y
référence dans un global cache
( cache['X -> Y'] = Y
), il serait alors poli de X.__del__
supprimer également l'entrée du cache.
Si vous savez que le destructor fournit (en violation de la directive ci - dessus) un nettoyage nécessaire, vous voudrez peut - être appeler directement , depuis à ce sujet il n'y a rien de spécial comme méthode: x.__del__()
. Évidemment, vous ne devriez le faire que si vous savez que cela ne vous dérange pas d'être appelé deux fois. Ou, en dernier recours, vous pouvez redéfinir cette méthode en utilisant
type(x).__del__ = my_safe_cleanup_method
__exit__
dans ce contexte? Est-il exécuté après ou avant__del__
ou ensemble?__del__
méthodes peuvent ne pas s'exécuter même à la fin du programme, et même lorsqu'elles s'exécutent à la fin, l'écriture d'une__del__
méthode qui fonctionne correctement même lorsque l'interpréteur est occupé à s'autodétruire autour de vous nécessite un codage plus soigneux que ce que de nombreux programmeurs appliquent. (Le nettoyage CPython obtient généralement des__del__
méthodes à exécuter à l'arrêt de l'interpréteur, mais il y a encore des cas où cela ne suffit pas. Les threads de démon, les globaux de niveau C et les objets__del__
créés dans un autre__del__
peuvent tous conduire à des__del__
méthodes qui ne s'exécutent pas.)J'ai rédigé la réponse à une autre question, bien que ce soit une question plus précise pour cela.
Comment fonctionnent les constructeurs et les destructeurs?
Voici une réponse légèrement opiniâtre.
N'utilisez pas
__del__
. Ce n'est pas du C ++ ou un langage conçu pour les destructeurs. La__del__
méthode devrait vraiment être supprimée dans Python 3.x, même si je suis sûr que quelqu'un trouvera un cas d'utilisation qui a du sens. Si vous devez l'utiliser__del__
, tenez compte des limitations de base par http://docs.python.org/reference/datamodel.html :__del__
est appelée lorsque le garbage collector collecte les objets, pas lorsque vous perdez la dernière référence à un objet et non lorsque vous exécutezdel object
.__del__
est responsable d'appeler n'importe lequel__del__
dans une superclasse, bien qu'il ne soit pas clair si c'est dans l'ordre de résolution de méthode (MRO) ou simplement appeler chaque superclasse.__del__
signifie que le ramasse-miettes abandonne la détection et le nettoyage des liens cycliques, comme la perte de la dernière référence à une liste liée. Vous pouvez obtenir une liste des objets ignorés à partir de gc.garbage. Vous pouvez parfois utiliser des références faibles pour éviter complètement le cycle. Cela est débattu de temps en temps: voir http://mail.python.org/pipermail/python-ideas/2009-October/006194.html .__del__
fonction peut tricher, enregistrer une référence à un objet et arrêter le garbage collection.__del__
sont ignorées.__del__
complète__new__
bien plus que__init__
. Cela devient déroutant. Voir http://www.algorithm.co.il/blogs/programming/python-gotchas-1- del -is-not-the-opposé-of- init / pour une explication et des pièges.__del__
n'est pas un enfant "bien-aimé" en Python. Vous remarquerez que la documentation de sys.exit () ne spécifie pas si les déchets sont collectés avant de quitter, et il y a beaucoup de problèmes étranges. L'appel de__del__
on globals provoque des problèmes d'ordre étrange, par exemple http://bugs.python.org/issue5099 . Doit être__del__
appelé même si l'__init__
échec? Voir http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 pour un long fil de discussion.Mais d'autre part:
__del__
signifie que vous n'oubliez pas d'appeler une déclaration de clôture. Voir http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/ pour un__del__
point de vue professionnel . Il s'agit généralement de libérer des ctypes ou une autre ressource spéciale.Et ma raison personnelle de ne pas aimer la
__del__
fonction.__del__
cela se transforme en trente messages de confusion.Alors, trouvez une raison de ne pas utiliser
__del__
.la source
__del__
, mais comment appeler__del__
, votre réponse est intéressante.La
__del__
méthode, elle sera appelée lorsque l'objet est garbage collection. Notez que l'appel n'est pas nécessairement garanti. Le code suivant ne le fera pas nécessairement:La raison en est que
del
décrémente simplement le nombre de références de un. Si quelque chose d'autre a une référence à l'objet,__del__
il ne sera pas appelé.Il y a cependant quelques mises en garde à utiliser
__del__
. En général, ils ne sont généralement pas très utiles. Il me semble que vous voulez utiliser une méthode close ou peut-être une instruction with .Consultez la documentation python sur les
__del__
méthodes .Une autre chose à noter: les
__del__
méthodes peuvent empêcher le garbage collection si elles sont surutilisées. En particulier, une référence circulaire qui a plus d'un objet avec une__del__
méthode ne sera pas récupérée. C'est parce que le garbage collector ne sait pas lequel appeler en premier. Consultez la documentation sur le module gc pour plus d'informations.la source
La
__del__
méthode (notez l'orthographe!) Est appelée lorsque votre objet est finalement détruit. Techniquement parlant (en cPython) c'est quand il n'y a plus de références à votre objet, c'est à dire quand il sort de la portée.Si vous souhaitez supprimer votre objet et appeler ainsi la
__del__
méthode utilisezqui supprimera l'objet (à condition qu'il n'y ait pas d'autres références à celui-ci).
Je vous suggère d'écrire un petit cours comme celui-ci
Et étudiez dans l'interpréteur python, par exemple
Notez que jython et ironpython ont des règles différentes quant au moment exact où l'objet est supprimé et
__del__
appelé.__del__
Cependant, il n'est pas considéré comme une bonne pratique à utiliser à cause de cela et du fait que l'objet et son environnement peuvent être dans un état inconnu lorsqu'il est appelé. Il n'est pas absolument garanti__del__
qu'il sera appelé non plus - l'interpréteur peut quitter de différentes manières sans supprimer tous les objets.la source
use del obj1
semble être une mauvaise idée sur laquelle s'appuyer.Comme mentionné précédemment, la
__del__
fonctionnalité n'est pas fiable. Dans les cas où cela peut sembler utile, envisagez d'utiliser les méthodes__enter__
et à la__exit__
place. Cela donnera un comportement similaire à lawith open() as f: pass
syntaxe utilisée pour accéder aux fichiers.__enter__
est automatiquement appelé lors de l'entrée dans la portée dewith
, while__exit__
est automatiquement appelé lors de sa sortie. Voir cette question pour plus de détails.la source