__del__
ist ein Finalizer . Es wird aufgerufen, wenn ein Objekt durch Müll gesammelt wird. Dies geschieht irgendwann, nachdem alle Verweise auf das Objekt gelöscht wurden.
In einem einfachen Fall kann dies direkt nach dem Sagen del x
oder, wenn x
es sich um eine lokale Variable handelt, nach dem Ende der Funktion erfolgen. Insbesondere wird CPython (die Standard-Python-Implementierung), sofern keine Zirkelverweise vorhanden sind, sofort Speicherbereinigung durchführen.
Dies ist jedoch ein Implementierungsdetail von CPython. Die einzige erforderliche Eigenschaft der Garbage Collection Python ist , dass es passiert , nachdem alle Verweise gelöscht wurden, so könnte dies nicht notwendig passiert direkt nach und kann nicht passieren .
Darüber hinaus können Variablen aus vielen Gründen eine lange Lebensdauer haben , z. B. kann eine sich ausbreitende Ausnahme oder eine Modul-Introspektion die Anzahl der Variablenreferenzen über 0 halten. Außerdem kann die Variable Teil des Referenzzyklus sein - CPython mit aktivierter Garbage Collection unterbricht die meisten Unterbrechungen , aber nicht alle, solche Zyklen, und selbst dann nur periodisch.
Da Sie keine Garantie dafür haben, dass es ausgeführt wird, sollten Sie niemals den Code einfügen, in den Sie ausgeführt werden müssen. __del__()
Stattdessen gehört dieser Code zur finally
Klausel des try
Blocks oder zu einem Kontextmanager in einer with
Anweisung. Es gibt jedoch gültige Anwendungsfälle für __del__
: Wenn ein Objekt beispielsweise X
auf Y
eine Y
Referenzkopie in einem globalen cache
( cache['X -> Y'] = Y
) verweist und diese aufbewahrt, ist es höflich X.__del__
, auch den Cache-Eintrag zu löschen.
Wenn Sie wissen, dass der Destruktor (unter Verstoß gegen die obige Richtlinie) eine erforderliche Bereinigung bereitstellt, möchten Sie diese möglicherweise direkt aufrufen , da sie als Methode nichts Besonderes enthält : x.__del__()
. Natürlich sollten Sie dies nur tun, wenn Sie wissen, dass es nichts ausmacht, zweimal angerufen zu werden. Als letzten Ausweg können Sie diese Methode mit neu definieren
type(x).__del__ = my_safe_cleanup_method
__exit__
in diesem Zusammenhang? Wird es nach oder vor__del__
oder zusammen ausgeführt?__del__
Methoden werden möglicherweise nicht einmal beim Beenden des Programms ausgeführt, und selbst wenn sie beim Beenden ausgeführt werden, erfordert das Schreiben einer__del__
Methode, die auch dann ordnungsgemäß funktioniert, wenn der Interpreter damit beschäftigt ist, sich selbst zu zerstören, eine sorgfältigere Codierung, als viele Programmierer anwenden. (Bei der CPython-Bereinigung werden normalerweise__del__
Methoden ausgeführt, die beim Herunterfahren des Interpreters ausgeführt werden. Es gibt jedoch immer noch Fälle, in denen dies nicht ausreicht. Daemon-Threads, Globals auf C-Ebene und Objekte,__del__
die in einem anderen erstellt wurden,__del__
können dazu führen, dass__del__
Methoden nicht ausgeführt werden.)Ich habe die Antwort auf eine andere Frage geschrieben, obwohl dies eine genauere Frage ist.
Wie funktionieren Konstruktoren und Destruktoren?
Hier ist eine leicht meinungsgebundene Antwort.
Nicht benutzen
__del__
. Dies ist kein C ++ oder eine Sprache für Destruktoren. Die__del__
Methode sollte in Python 3.x wirklich weg sein, obwohl ich sicher bin, dass jemand einen Anwendungsfall finden wird, der Sinn macht. Beachten Sie bei Bedarf__del__
die grundlegenden Einschränkungen unter http://docs.python.org/reference/datamodel.html :__del__
wird aufgerufen, wenn der Garbage Collector zufällig die Objekte sammelt, nicht wenn Sie den letzten Verweis auf ein Objekt verlieren und nicht wenn Sie es ausführendel object
.__del__
ist für das Aufrufen von Elementen__del__
in einer Oberklasse verantwortlich, obwohl nicht klar ist, ob dies in der Reihenfolge der Methodenauflösung (MRO) erfolgt oder nur jede Oberklasse aufgerufen wird.__del__
Mittel gibt der Garbage Collector das Erkennen und Bereinigen von zyklischen Links auf, z. B. den Verlust des letzten Verweises auf eine verknüpfte Liste. Sie können eine Liste der Objekte erhalten, die von gc.garbage ignoriert werden. Sie können manchmal schwache Referenzen verwenden, um den Zyklus insgesamt zu vermeiden. Dies wird ab und zu diskutiert: siehe http://mail.python.org/pipermail/python-ideas/2009-October/006194.html .__del__
Funktion kann betrügen, einen Verweis auf ein Objekt speichern und die Speicherbereinigung stoppen.__del__
ausgelöst werden, werden ignoriert.__del__
ergänzt__new__
weit mehr als__init__
. Das wird verwirrend. Eine Erklärung und Fallstricke finden Sie unter http://www.algorithm.co.il/blogs/programming/python-gotchas-1- del- is-not-the-Gegenteil-von- init / .__del__
ist kein "geliebtes" Kind in Python. Sie werden feststellen, dass in der Dokumentation zu sys.exit () nicht angegeben ist, ob vor dem Beenden Müll gesammelt wird, und es gibt viele seltsame Probleme. Das Aufrufen von__del__
on globals führt zu ungewöhnlichen Ordnungsproblemen, z . B. http://bugs.python.org/issue5099 . Sollte__del__
angerufen werden, auch wenn das__init__
fehlschlägt? Einen langen Thread finden Sie unter http://mail.python.org/pipermail/python-dev/2000-March/thread.html#2423 .Andererseits:
__del__
bedeutet, dass Sie nicht vergessen, eine schließende Anweisung aufzurufen. Unter http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/ finden Sie eine Pro-__del__
Sichtweise. Hier geht es normalerweise darum, ctypes oder eine andere spezielle Ressource freizugeben.Und mein pesonaler Grund, die
__del__
Funktion nicht zu mögen .__del__
wenn jemand etwas anspricht, entstehen dreißig verwirrende Botschaften.Finden Sie also einen Grund, nicht zu verwenden
__del__
.quelle
__del__
, sondern wie Sie anrufen__del__
, ist Ihre Antwort interessant.Die
__del__
Methode wird aufgerufen, wenn das Objekt durch Müll gesammelt wird. Beachten Sie jedoch, dass der Aufruf nicht unbedingt garantiert ist. Der folgende Code allein reicht nicht unbedingt aus:Der Grund dafür ist, dass
del
nur die Referenzanzahl um eins verringert wird. Wenn etwas anderes einen Verweis auf das Objekt hat,__del__
wird es nicht aufgerufen.Es gibt jedoch einige Einschränkungen bei der Verwendung
__del__
. Im Allgemeinen sind sie normalerweise nicht sehr nützlich. Es klingt für mich eher so, als ob Sie eine Close-Methode oder vielleicht eine with-Anweisung verwenden möchten .Weitere Informationen finden
__del__
Sie in der Python-Dokumentation zu Methoden .Eine andere Sache zu beachten:
__del__
Methoden können die Speicherbereinigung verhindern, wenn sie überbeansprucht werden. Insbesondere bei einem Zirkelverweis, der mehr als ein Objekt mit einer__del__
Methode enthält, wird kein Müll gesammelt. Dies liegt daran, dass der Garbage Collector nicht weiß, welchen er zuerst aufrufen soll. Weitere Informationen finden Sie in der Dokumentation zum GC-Modul .quelle
Die
__del__
Methode (Rechtschreibung beachten!) Wird aufgerufen, wenn Ihr Objekt endgültig zerstört ist. Technisch gesehen (in cPython) bedeutet dies, dass keine Verweise mehr auf Ihr Objekt vorhanden sind, dh wenn es außerhalb des Gültigkeitsbereichs liegt.Wenn Sie Ihr Objekt löschen und damit die
__del__
Methode aufrufen möchten, verwenden SieDadurch wird das Objekt gelöscht (vorausgesetzt, es gab keine anderen Verweise darauf).
Ich schlage vor, Sie schreiben eine kleine Klasse wie diese
Und untersuchen Sie im Python-Interpreter, z
Beachten Sie, dass Jython und Ironpython unterschiedliche Regeln haben, wann genau das Objekt gelöscht und
__del__
aufgerufen wird.__del__
Aufgrund dessen und der Tatsache, dass sich das Objekt und seine Umgebung beim Aufrufen möglicherweise in einem unbekannten Zustand befinden, wird die Verwendung jedoch nicht als bewährte Methode angesehen . Es ist auch nicht absolut garantiert__del__
, dass es aufgerufen wird - der Interpreter kann auf verschiedene Arten beendet werden, ohne alle Objekte zu löschen.quelle
use del obj1
scheint wie eine schlechte Idee zu vertrauen.Wie bereits erwähnt, ist die
__del__
Funktionalität etwas unzuverlässig. In Fällen, in denen dies nützlich erscheint, sollten Sie stattdessen die Methoden__enter__
und__exit__
verwenden. Dies führt zu einem ähnlichen Verhalten wie diewith open() as f: pass
Syntax für den Zugriff auf Dateien.__enter__
genannt wird , automatisch , wenn der Umfang der Eingabewith
, während__exit__
automatisch beim Austritt aus aufgerufen wird. Weitere Informationen finden Sie in dieser Frage .quelle