Ich arbeite in Python 2.7 und ich mochte dieses Problem, das mich verwirrt.
Das ist das einfachste Beispiel:
%Vor% Das ist OK wie erwartet ... jetzt versuche ich, die Methode a()
des Objekts a
zu ändern und was passiert ist, dass ich nach der Änderung% ce_de% nicht mehr löschen kann:
Nur um einige Überprüfungen durchzuführen, habe ich die a
Referenz vor und nach der Zuweisung ausgedruckt
Schließlich habe ich a.a
Modul verwendet, um zu verstehen, warum das Objekt nicht freigegeben wurde:
%Vor%
Wie Sie im objgraph
image sehen können, gibt es post-backref-graph.png
Referenzen in b, die für mich keinen Sinn ergeben, da die Selbstreferenzen der Instanzmethode ignoriert werden sollten (wie vor der Zuweisung).
Jemand kann erklären, warum dieses Verhalten und wie kann ich es umgehen?
Wenn Sie a.a
schreiben, wird effektiv Folgendes ausgeführt:
, weil Sie nicht auf eine vorgebundene Methode, sondern auf die Klassenmethode zugreifen Zur Laufzeit gebunden.
Wenn Sie
tun %Vor% Sie "cachen" effektiv den Akt des Bindens der Methode. Da die gebundene Methode eine Referenz auf das Objekt hat (offensichtlich, da sie self
an die Funktion übergeben muss), erzeugt dies eine zirkuläre Referenz.
Also modelliere ich dein Problem wie folgt:
%Vor% Sie können schwache Referenzen verwenden, um bei Bedarf in lof_all_calls
like:
Das ist wirklich hässlich, also würde ich es lieber herausziehen, um einen weakmethod
Dekorator zu erstellen:
Fertig!
FWIW, Python 3.4 hat nicht nur diese Probleme, es hat auch WeakMethod
für Sie vorgefertigt.
Vedracs Antwort über die gebundene Methode, die einen Verweis auf die Instanz enthält, ist nur ein Teil der Antwort. CPythons Garbage Collector weiß, wie man zyklische Referenzen erkennt und behandelt - außer wenn ein Objekt, das Teil des Zyklus ist, eine __del__
-Methode hat, wie hier erwähnt Ссылка :
Objekte, die
__del__()
Methoden haben und Teil eines Referenzzyklus sind verursachen, dass der gesamte Referenzzyklus nicht eingreifbar ist, einschließlich Objekte nicht unbedingt im Zyklus, sondern nur von dort erreichbar. Python sammelt solche Zyklen nicht automatisch, da im Allgemeinen es ist Python nicht möglich, eine sichere Reihenfolge zu erraten, in der der Befehl ausgeführt werden soll__del__()
Methoden. (...) Es ist im Allgemeinen besser, das Problem zu vermeiden, indem Sie keine Zyklen erstellen, die Objekte mit__del__()
Methoden enthalten, und Müll kann in diesem Fall untersucht werden, um zu verifizieren, dass solche Zyklen nicht vorliegen erstellt werden.
IOW: Entfernen Sie Ihre __del__
Methode und Sie sollten in Ordnung sein.
EDIT: wrt / Ihr Kommentar:
Ich verwende es für das Objekt als Funktion
a.a = functor(a.a)
. Wenn der Test Ist fertig Ich möchte den Funktor durch die ursprüngliche Methode ersetzen.
Dann ist die Lösung einfach und einfach:
%Vor% Bis Sie es explizit binden, hat a
kein 'a' Instanzattribut, also wird es nach der Klasse gesucht und eine neue method
Instanz wird zurückgegeben (cf Ссылка für mehr dazu). Diese method
Instanz wird dann aufgerufen und (normalerweise) verworfen.
Warum Python das macht. Technisch gesehen enthalten Objekte all zirkuläre Referenzen, wenn sie Methoden haben. Die Garbage Collection würde jedoch wesentlich länger dauern, wenn der Garbage Collector eine explizite Überprüfung von Objektmethoden durchführen müsste, um sicherzustellen, dass das Objekt nicht beschädigt wird. Daher speichert Python die Methoden separat vom __dict__
eines Objekts. Wenn Sie also a.a = a.a
schreiben, überschatten Sie die Methode mit sich selbst im Feld a
des Objekts. Daher gibt es einen expliziten Verweis auf die Methode, die verhindert, dass das Objekt ordnungsgemäß freigegeben wird.
Die Lösung Ihres Problems besteht nicht darin, einen "Cache" der ursprünglichen Methode beizubehalten und die schattierte Variable einfach zu löschen, wenn Sie damit fertig sind. Dadurch wird die Methode ausgeblendet und wieder verfügbar gemacht.
%Vor% Hier zeigt vars
an, was sich im Attribut __dict__
eines Objekts befindet. Beachten Sie, dass __dict__
keinen Verweis auf sich selbst enthält, obwohl a.__dict__
gültig ist. dir
erzeugt eine Liste aller Attribute, die von dem gegebenen Objekt erreichbar sind. Hier können wir alle Attribute und Methoden eines Objekts und alle Methoden und Attribute seiner Klassen und ihrer Basen sehen. Dies zeigt, dass die gebundene Methode von a
separat an der Stelle gespeichert wird, an der a
's Attribute gespeichert sind.
Tags und Links python memory-leaks