Für jemanden, der neu bei Python ist, verstehe ich nicht, wie man eine Instanz einer Klasse aus einer rekursiven Funktion entfernt.
Betrachten Sie diesen Code eines k-d-Baums :
%Vor%Der wichtige Teil ist dies:
%Vor% Wie kann ich die aktuelle Instanz löschen?
Die del self
oder self=None
oder mein Ansatz funktioniert NICHT
Was du versuchst zu tun, ergibt keinen Sinn in Worten, geschweige denn in Python. Was Sie tun möchten, ist den Knoten aus der Struktur entfernen. Sie haben jedoch kein Baumobjekt, Sie haben nur Knoten. Wie können Sie den Knoten aus dem Baum entfernen, wenn kein Baum vorhanden ist, aus dem er entfernt werden könnte?
Wenn Sie großzügig sind, könnten Sie argumentieren, dass Sie den Baum ohne eine explizite Baumklasse implementieren, indem Sie sagen, dass eine Sammlung von Knoten ein Baum ist. Aber dann hast du das Problem, wie sieht ein leerer Baum aus? Außerdem benötigt der Client des Baums einen Verweis auf den Baum (damit er Knoten hinzufügen und entfernen kann). Da Sie jedoch kein Baumobjekt haben, kann er nur einen Verweis auf einen Knoten haben. Daher ist der Client der einzige mit der Fähigkeit, den Baum zu leeren, was er tun muss, indem er seine Referenz auf den Knoten löscht. Es ist für ein Objekt in Python nicht möglich, beliebige Referenzen auf sich selbst von anderen Objekten zu entfernen, ohne diese Objekte zu kennen . Daher kann sich Ihr Wurzelknoten im Allgemeinen nicht aus der "Struktur" löschen, was das Löschen der Referenz auf den Knoten, den der Client hält. Um dies zu implementieren, würde eine definierte Schnittstelle zwischen dem Wurzelknoten und dem Client benötigt. Wenn der Client sagt "Lösche diesen Knoten" kann der Wurzelknoten antworten und sagen "das bin ich selbst, also lösche mich und du hast einen leeren Baum" . Aber das wäre ein Schmerz.
Auch eine implizite konzeptuelle Struktur, die eine Sammlung von Knoten ist, geht gegen das Zen von Python :
Explizit ist besser als implizit.
Ich schlage daher vor, dass Sie eine explizite einfache Baumklasse implementieren, die leer sein kann und auf die Ihr Client verweisen kann. Wenn Sie es wie einen Knoten aussehen lassen, kann es einfach das übergeordnete Element des Stammknotens sein und, soweit es den Stammknoten betrifft, ist es (der Stammknoten) ein normaler Unterknoten. Etwas wie (Vorbehalt: nicht getestet und angenommen, dass die obige Funktion remove()
wirklich eine Methode für eine Knotenklasse ist) :
Dann macht der Client Dinge wie:
%Vor%Bevor Sie sich Python anschauen, überlegen Sie sich den folgenden C / C ++ - Code:
%Vor% Zuerst wird explizit ein Objekt vom Typ A
erstellt. Dies läuft darauf hinaus, ein kleines Stück Speicher zuzuweisen und zu initialisieren (das einzige, was im Objekt gespeichert ist, ist ein Zeiger auf die suicide
-Funktion) und die Variable a
auf dieses Stück Speicher zu setzen.
Als nächstes wird die Funktion suicide
aufgerufen, die die Laufzeitumgebung bittet, den Speicher für das Objekt durch Aufruf von delete this
freizugeben. Dies ist eine absolut gültige Operation, obwohl es nicht etwas ist, was Sie normalerweise im wirklichen Leben tun würden Code. Nach dem Aufruf von a->suicide()
wird nämlich der Zeiger a
ungültig, weil der Speicher, auf den er weiterhin zeigt, nicht mehr vorhanden ist. Wenn Sie zum Beispiel versuchen, a->suicide()
später erneut aufzurufen, erhalten Sie einen Segmentierungsfehler (weil Sie zum Aufrufen von a->suicide
den Zeiger auf die Methode suicide
in dem Speicher nachschlagen müssen, auf den a
zeigt , und dieser Speicher ist nicht mehr gültig).
Aber sinnvoll oder nicht, Sie können ein C / C ++ - Objekt (dh seinen Speicher) von einem beliebigen Ort aus zerstören, einschließlich der eigenen Methode des Objekts (vorausgesetzt, es wurde auf dem Heap von Natürlich).
Lasst uns nun zu Python zurückkehren. In Python ist die Situation anders. Obwohl Sie Objekte explizit in Python erstellen, wie Sie es in C / C ++ tun, können Sie ihren Speicher nicht zwangsweise freigeben. Der gesamte Speicher wird vom Garbage Collector verwaltet, der verfolgt, welche Objekte gerade referenziert werden, welche nicht referenziert werden und die nicht erreichbaren Objekte löschen. in den Momenten, in denen es sich dafür entscheidet .
Obwohl die Python-Anweisung del self
syntaktisch ähnlich wie delete this
in C / C ++ aussieht, ist sie wirklich etwas völlig anderes . Es ist nicht eine Anweisung an den Speichermanager, den Speicher zu löschen. Stattdessen wird einfach der Schlüssel self
aus dem Wörterbuch "lokale Variablen" entfernt. Der entsprechende Wert (d. H. Der Speicher self
referenzierte) bleibt irgendwo auf dem Heap noch ausgesetzt.
Natürlich, wenn niemand sonst auf diesen Speicher zeigt, ist es wahrscheinlich, dass der Garbage Collector sie bald freigibt (obwohl dies nicht garantiert ist, weil es wirklich vom verwendeten GC Algorithmus abhängt), aber wie du es getan hast del self
, jemand ist , der immer noch auf den Speicher zeigt, weil dieser gerade die Methode aufgerufen hat.
Betrachten Sie eine "wörtliche Übersetzung" des obigen C / C ++ - Codes in Python:
%Vor% Es ist auch absolut gültiger Python-Code, aber del self
tut nichts (außer dass Sie später in derselben Methode nicht mehr auf self
verweisen können, weil Sie die Variable aus dem Bereich gelöscht haben).
Solange eine Variable a
existiert, die von irgendwo auf das erstellte Objekt verweist, wird ihr Speicher nicht freigegeben. So wie die Erinnerung hier nicht veröffentlicht würde, zum Beispiel:
Zum besseren Verständnis schlage ich vor, dass Sie auch die Bedeutung von del d[key]
in Python mit delete d[key]
in C / C ++ vergleichen.