__del__ Methode in Python genannt wird, wenn es nicht zu erwarten
-
20-09-2019 - |
Frage
Ich bin neu in Python und haben in Swaroop CH „A Byte of Python“ durch die Beispiele gearbeitet. Ich bin ein bestimmtes Verhalten mit der __del__
Methode sehen, die mich ist rätselhaft.
Grundsätzlich, wenn ich das folgende Skript ausführen (in Python 2.6.2)
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
def __del__(self):
'''I am dying'''
print '%s says bye' % self.name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
swaroop = Person4('Swaroop')
kaleem = Person4('Kalem')
mit der Python-Konsole (oder den Spyder interaktive Konsole) Ich sehe die folgende:
execfile (U'c: \ 1_eric \ Python \ test1.py ')
Initializing Swaroop
Initializing Kalemexecfile (U'c: \ 1_eric \ Python \ test1.py ')
Initializing Swaroop
Swaroop sagt bye
Ich bin der letzte
Initializing Kalem
Kalem sagt bye
Ich bin der letzte
Warum ist die __del__
Methode wird unmittelbar nach dem __init__
auf dem zweiten Lauf genannt?
Ich vermute, dass da die gleichen Instanznamen ( ‚swaroop‘ und ‚Kaleem‘) verwendet werden, dass es die ursprüngliche Instanz freigibt und Müll sammeln sie. Aber, so scheint dies mit der aktuellen Bevölkerungszahl spielte Chaos werden.
Was ist denn hier los?
Was ist ein guter Weg, um diese Art von Verwirrung zu vermeiden?
Vermeiden Sie den Einsatz von __del__
?
Überprüfen Sie, ob vorhandene Instanz Namen, bevor sie wiederverwendet?
...
Danke, Eric
Lösung
Allgemeine Hinweise: Benutzen Sie nicht __ __ del in Python. Es kann Garbage Collection in einer Reihe von Möglichkeiten, esp brechen. im Fall von zirkulären Verweisen zwischen Objekten.
In Ihrem Beispiel dort ist verschiedene Fragen im Zusammenhang mit der Verwendung von execfile () - das ist keine bewährte Methode - und die Neudefinition der globalen Variablen. By the way, wenn Sie wirklich ein pseudo-destructor (dh ein Code, der aufgerufen wird, wenn das Objekt Müll gesammelt wird) erstellen müssen, schreiben Sie eine so genannte „Finalizerthread“ -Funktion (es ist nicht richtig ein destructor) und rufen Sie es mit WeakRef .ref Rückruf. Es soll nicht eine Instanzmethode natürlich sein, und denken Sie daran, dass Lambda tatsächlich schafft einen Verschluss, daher sicher sein, keinen Hinweis auf Selbst in dem Rückruf zu lecken! Wenn Sie Daten aus dem zerstörten Instanz müssen, verwenden Sie das Argument Ansatz func standardmäßig nur sicher sein, nie , um Referenz ‚Selbst‘ im Inneren des Lambda, sonst wird es nicht funktionieren.
from weakref import ref
from time import sleep
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
self._wr = ref(self, lambda wr, name=self.name: Person4_finalizer(name))
def Person4_finalizer(name):
'''I am dying'''
print '%s says bye' % name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
p1 = Person4("one")
p2 = Person4("two")
p3 = Person4("three")
del p2
del p3
sleep(5)
Ausgang (der Schlaf ist da, um Hilfe zu sehen, was passiert):
Initializing one
Initializing two
Initializing three
two says bye
There are still 2 left
three says bye
There are still 1 left
one says bye
I am the last one
Andere Tipps
Es gibt ein paar Dinge, hier geht. Wenn Ihre Person4
Klasse instanziiert wird, es seine population
Klassenvariable auf 0 aus Ihrer interaktiven Konsole initialisiert, erscheinen Sie Ihre „test1.py“ Datei mehrere Male ausgeführt werden. Das zweite Mal, wenn Sie es ausführen, wird die Person4
Klasse wieder erklärt, die es macht technisch andere von dem ersten (obwohl sie den gleichen Namen haben). Das heißt es hat einen eigenen, unabhängigen population
zählen.
Nun swaroop
und kaleem
sind global Variablen, zwischen den beiden Ihre Instanzen "test1.py" geteilt. Python verwendet intern Referenzzählung für die meisten seiner automatischen Speicherbereinigungs, so dass die ursprüngliche Instanz der ersten Klasse Person4
wird erst in der zweiten Zuweisung zu swaroop
freigegeben. Zuordnen zu swaroop
dekrementiert den Referenzzähler für die erste Instanz, __del__
verursacht genannt zu werden, weil der Referenzzähler jetzt Null ist. Aber weil Sie zu Person4
namentlich innerhalb __del__()
Bezug genommen wird, wenn die zurück Instanz verschwindet es verringert die neue Person4.population
Zahl, anstelle der alten Person4
Bevölkerungszahl.
Wir hoffen, dass Sinn. Ich kann sehen, warum dies könnte jemand Lernen Python verwirrend sein. Ihre Nutzung von Klassenvariablen zur gleichen Zeit wie die Neudefinition der Person4
Klasse execfile()
mit weiter verwirrend Angelegenheiten. Für was es wert ist, habe ich eine Menge von Python-Code geschrieben, und ich glaube nicht, habe ich immer die __del__
spezielle Methode benötigt verwenden.