Destruktoren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
cime
User
Beiträge: 152
Registriert: Dienstag 24. Mai 2005, 15:49

gibt es eigentlich in Python eine Möglichkeit, Objekten irgendwie Destruktoren zuzuweisen????

würde mich mal interresieren, da könnt ich in manchen programmen nämlich einiges vereinfachen ...

mfg cime
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Ja, Konstruktoren heißen __init__, Destruktoren __del__
raist1314
User
Beiträge: 52
Registriert: Dienstag 21. September 2004, 06:58
Wohnort: Adelzhausen
Kontaktdaten:

Da wär ich aber vorsichtig mit, da __del__ meines Wissens nach erst ausgeführt wird, wenn der garbage collector mitkriegt, dass dein Objekt nicht mehr verwendet wird und es aufräumt. Wenn Du dein Ojekt aber explizit mit

Code: Alles auswählen

del meinObjekt
löschts, wird __del__ anscheinend sofort ausgeführt. Ich weiss aber nicht, ob das verlässlich ist. Es kann auch sein, dass das Objekt zur zum Löschen für den GC markiert wird, das weiss ich nicht genau.

Sebastian
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

raist1314 hat geschrieben:Es kann auch sein, dass das Objekt zur zum Löschen für den GC markiert wird
Genauso ist es:

Code: Alles auswählen

>>> class Foo:
...  def __del__(self):
...   print "bye"
...
>>> a = Foo()
>>> b = a
>>> del a
>>> del b
bye
raist1314
User
Beiträge: 52
Registriert: Dienstag 21. September 2004, 06:58
Wohnort: Adelzhausen
Kontaktdaten:

Das dachte ich mir... also eher ne unsichere Sache...

Sebastian
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

raist1314 hat geschrieben:Das dachte ich mir... also eher ne unsichere Sache...

Sebastian
Ja, interessant, dann ist der Sinn von __del__ ein anderer,
als man es sich so vorstellt. :?

von der Python Docu:

"del x" doesn't directly call x.__del__() -- the former decrements the reference count for x by one, and the latter is only called when x's reference count reaches zero.

Nur bei der letzten zu löschenden Instanz wird __del__ aufgerufen.
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

Also ich hab mir das instinktiv immer so vorgestellt :-)
Unter C würde ich auch keinen Destruktor eines Objekts aufrufen, auf das noch ein pointer verweist. (Habs oft genug unabsichtlich gemacht, ein Grund warum ich jetzt Python bevorzuge)

Ich denke das grundsätzliche Verständnisproblem, wenn man es denn so nennen darf, liegt darin, dass man del in python nur den Verweis auf ein Objekt löscht, während es in C++ wirklich das Objekt zerstört.

(Ist auch sehr pythonic nebenbei, weil mit dem c++-del würd ich implizit den "wert" einer anderen variable verändern, die noch auf mein gelöschtes Objekt verweist. Explicit is better than implicit.)
cime
User
Beiträge: 152
Registriert: Dienstag 24. Mai 2005, 15:49

__del__ ist genau das, wonach ich gesucht habe ... thx ...
Francesco hat geschrieben:von der Python Docu:

"del x" doesn't directly call x.__del__() -- the former decrements the reference count for x by one, and the latter is only called when x's reference count reaches zero.
PS: wo in der doku steht das eigentlich genau (ich find mich in der Pythondoku immer nich so wirklich zurecht)???
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

cime hat geschrieben:__del__ ist genau das, wonach ich gesucht habe ... thx ...
Francesco hat geschrieben:von der Python Docu:

"del x" doesn't directly call x.__del__() -- the former decrements the reference count for x by one, and the latter is only called when x's reference count reaches zero.
PS: wo in der doku steht das eigentlich genau (ich find mich in der Pythondoku immer nich so wirklich zurecht)???
ich gehe meist so vor (WinXP):
Ich verwende C:\Python24\Doc\Python24.chm (shortcut am desktop, da
die häufig gebraucht wird).
Ich verwende nicht den inhalt, da ich durch "Suchen" meist viel schneller
zum Ziel komme. __del__ suchen, dann ist der erste Eintrag
3.3.1 "Basic customization", das mir im gelben Feld "Note:" die erforderliche Information brachte.

@henning:
Kann mich damit (noch) nicht recht anfreunden.
Wozu brauche ich dann eine __del__ Funktion überhaupt.
Was macht es für einen Sinn, wenn bei der letzten Instanz einer Klasse
dann der "Destruktor" aufgerufen wird.

Für mich logischer:
del object =>__del__ (dann ist die referenz weg und das object auch)
wenn ich versuche, es aufzurufen, dann bekomme ich ohnehin einen NameError.
BlackJack

cime hat geschrieben:__del__ ist genau das, wonach ich gesucht habe ...
Da wär ich mir nicht sicher. Die Methode wird erst aufgerufen wenn das Objekt wirklich vom Interpreter/Garbage Collector freigegeben wird. Wann dieser Zeitpunkt kommt ist nicht sicher. Auch bei CPython kann es sein, das es erst beim "herunterfahren" des Interpreters passiert. Und dann solltest Du in `__del__()` nichts mehr benutzen von dem Du nicht ganz sicher bist noch eine Referenz zu haben. Selbst ein `print` kann dann ein Problem werden, wenn `sys.stdout` schon "abgeräumt" wurde.

Lass die Finger von `__del__()` und stelle lieber eine Methode bereit, die Du explizit aufrufst, wenn Du mit dem Objekt fertig bist.
BlackJack

Francesco hat geschrieben:@henning:
Kann mich damit (noch) nicht recht anfreunden.
Wozu brauche ich dann eine __del__ Funktion überhaupt.
Was macht es für einen Sinn, wenn bei der letzten Instanz einer Klasse
dann der "Destruktor" aufgerufen wird.
Du brauchst keine `__del__()` Methode. So einfach ist das. :-)

Die Methode wird nicht bei der letzten Instanz einer Klasse aufgerufen sondern dann wenn keine Referenz mehr auf das Objekt verweist. Wie unsinnig wäre es denn bitteschön ein Objekt zu zerstören, auf das noch zugegriffen werden kann!?
Für mich logischer:
del object =>__del__ (dann ist die referenz weg und das object auch)
wenn ich versuche, es aufzurufen, dann bekomme ich ohnehin einen NameError.
Das spiegelt aber überhaupt nicht die Funktionsweise von Python wieder. Das erste Missverständnis scheint schon durch die Namenswahl bei ``del object`` durch: Du löscht mit ``del`` kein Objekt sondern den Namen!

Code: Alles auswählen

In [6]: a_name = object()

In [7]: a_name
Out[7]: <object object at 0x40056440>

In [8]: another_name = a_name

In [9]: del a_name

In [10]: a_name
---------------------------------------------------------------------------
exceptions.NameError                                 Traceback (most recent call last)

/home/bj/<console>

NameError: name 'a_name' is not defined

In [11]: another_name
Out[11]: <object object at 0x40056440>
Wenn bei ``del a_name`` wirklich das Objekt vernichtet worden wäre, was hättest Du denn dann erwartet wenn man über ``another_name`` auf das Objekt zugreift?
henning
User
Beiträge: 274
Registriert: Dienstag 26. Juli 2005, 18:37

Francesco hat geschrieben:
@henning:
Kann mich damit (noch) nicht recht anfreunden.
Wozu brauche ich dann eine __del__ Funktion überhaupt.
Was macht es für einen Sinn, wenn bei der letzten Instanz einer Klasse
dann der "Destruktor" aufgerufen wird.
Warum stört ihr euch alle so sehr daran den Zeitpunkt der Zerstörung nicht genau festlegen zu können?

Also warum __del__ nützlich sein kann:
Nehmen wir an, du hast ein Objekt mit dem du eine Verbindung repräsentierst, zum Beispiel zu einem FTP-Server oder was-weiß ich.
Wenn das Objekt zerstört wird, macht es Sinn, zu gucken, ob die Verbindung noch besteht und wenn nicht, diese höflich (z.B. mit einem QUIT) zu beenden.

Zugegeben, man braucht es nicht oft, aber es kann nützlich sein.

Zur Zeitpunkt-Sache:
Wenn man so coded, dass man mit dem Löschen eines Objekts eigentlich Funktionen ausführen will, die nicht unmittelbar mit der Objektzerstörung zu tun haben, dann macht man ja eh irgendwas falsch.
Andernfalls sollte der genaue Zeitpunkt kein Problem darstellen.

Und falls irgendwie doch und es total wichtig ist, dass __del__ genau in dem Moment ausgeführt wird, in dem die letzte Referenz auf das Objekt erlischt, muss man halt den garbage-collector ausschalten. (Dann muss man aber aufpassen keine zirkulären Referenzen zu haben!)

(Wobei ich mir bei dem gc-Kram nicht so sicher bin)
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

__del__ kann ihc beispiels weise verwenden wenn ich in einem webapplication thread die geteilte datenbankverbindung trennen will.
TUFKAB – the user formerly known as blackbird
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

raist1314 hat geschrieben:Das dachte ich mir... also eher ne unsichere Sache...
Wieso unsicher? Wenn jemand die Instanz noch benutzt, darf sie doch nicht einfach gelöscht werden!

In C++ kann man da ganz schön auf die Nase fallen:

Code: Alles auswählen

void Foobar::Finish(){
  delete this;
}
Wenn nun zwei Programmteile einen Foobar* auf die selbe Instanz halten, und eine ruft Finish auf, weil sie fertig ist, stürzt das Programm ab, sobald der andere Teil versucht, darauf zuzugreifen.

Genau dieses Verhalten von Python will man in C++ doch auch gerne haben; deswegen gibt es ja auto_ptr und weitere smart pointer. Es gibt sogar einen Garbagecollector für C++.

Oder worauf wolltest du hinaus?
BlackJack

blackbird hat geschrieben:__del__ kann ihc beispiels weise verwenden wenn ich in einem webapplication thread die geteilte datenbankverbindung trennen will.
Nur wenn Du damit leben kannst, das nicht sicher gestellt ist, das __del__ wirklich irgendwann vor Programmende aufgerufen wird. Also bei einem Server der sehr lange läuft eben auch sehr spät.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

BlackJack hat geschrieben:Nur wenn Du damit leben kannst, das nicht sicher gestellt ist, das __del__ wirklich irgendwann vor Programmende aufgerufen wird. Also bei einem Server der sehr lange läuft eben auch sehr spät.
Das ist ja auch Sinn einer persistenten Datenbankverbindung :-)
TUFKAB – the user formerly known as blackbird
Antworten