Seite 1 von 2
Vererbung / self
Verfasst: Dienstag 20. Januar 2009, 08:04
von Dr.Miles
Hallo, ich verstehe in diesem Beispiel nicht, warum das geerbte von Schulmitglied mit SchulMitglied.__init__(self, name, alter) initialisiert wird. Erwartet hätte ich sowas wie self.__init__(self,name,alter). Also in anderen Worten: Rufe von deinem eigenen Objekt die Methode init auf, da das init von Schulmitglied ja jetzt in der Unterklasse ist?
Und wann gibt man das self mit und wann nicht?
Code: Alles auswählen
#!/usr/bin/python
class SchulMitglied:
'''Repraesentiert ein beliebiges Mitglied der Hochschule.'''
def __init__(self, name, alter):
self.name = name
self.alter = alter
print '(SchulMitglied %s initialisiert)' % self.name
def auskunft(self):
'''Gib Auskunft ueber das Mitglied.'''
print 'Name: "%s" Alter: "%s"' % (self.name, self.alter),
class Dozent(SchulMitglied):
'''Repraesentiert einen Dozenten der Hochschule.'''
def __init__(self, name, alter, gehalt):
SchulMitglied.__init__(self, name, alter)
self.gehalt = gehalt
print '(Dozent %s initialisiert)' % self.name
Gruß
Dr.Miles
Re: Vererbung / self
Verfasst: Dienstag 20. Januar 2009, 08:23
von cofi
Dr.Miles hat geschrieben:Also in anderen Worten: Rufe von deinem eigenen Objekt die Methode init auf, da das init von Schulmitglied ja jetzt in der Unterklasse ist?
Und wann gibt man das self mit und wann nicht?
Der Gedankengang ist schon richtig, aber du vergisst, dass du gerade die init-Methode überschreibst, d.h. du würdest damit maximal Rekursion erzeugen
Das self gibt man mit, damit auch die aktuelle Klasse durch die geerbte Methode initialisiert wird.
Es gibt auch die Built-in Funktion super, aber
das sollte man berücksichtigen.
Re: Vererbung / self
Verfasst: Dienstag 20. Januar 2009, 09:09
von Dr.Miles
cofi hat geschrieben:Es gibt auch die Built-in Funktion super, aber
das sollte man berücksichtigen.
Danke, das schau ich mir an, wenn ich dort etwas Durchblick habe, denke noch was neues verwirrt mich im Moment noch mehr.
Habe jetzt ein anderes problem und zwar habe ich das mit der vererbung geübt und bekomme jetzt eine Exception, die ich nicht ganz verstehe:
Exception exceptions.AttributeError: "'NoneType' object has no attribute 'Anzahl'" in <bound method Panzer.__del__ of <__main__.Panzer instance at 0x7fada06fce18>> ignored
Das trat in diesem Code auf:
Code: Alles auswählen
class Vehikel :
Anzahl = 0
def __init__(self,name,ps) :
self.name = name
self.ps = ps
Vehikel.Anzahl += 1
def __del__(self):
Vehikel.Anzahl -= 1
class Panzer(Vehikel) :
def __init__(self,name,ps,panzerung,bewaffnung) :
Vehikel.__init__(self,name,ps)
self.panzerung = panzerung
self.bewaffnung = bewaffnung
def feuern(self) :
self.bewaffnung -= 1
def beschuss(self) :
self.panzerung -= 1
def status(self) :
print self.name , self.panzerung , self.bewaffnung
leopard = Panzer("leopard",455,100,100)
leopard.feuern()
leopard.status()
Ich lese das als:
Die __del__- Methode in Klasse Panzer (also die geerbte von Vehikel) findet bei "nichts" kein Attribut Anzahl, welches es dekrementieren kann...
Aber da steht doch, das es vehikel.Anzahl dekrementieren soll?
Gruß
Dr.Miles
Verfasst: Dienstag 20. Januar 2009, 09:36
von Pekh
Der Gebrauch von __del__ ist leider etwas problematisch, weil nicht genau gesagt werden kann, wann diese Methode intern aufgerufen wird.
Bei dir scheint es ja um die Anzahl der noch verbleibenden Panzer auf dem Spiel- / Schlachtfeld zu gehen. Sowas kriegst du wesentlich zuverlässigerer und sauberer über eine Liste (z.B. als Attribut des Spielfeldes) hin, in die du alle Einheiten einträgst.
Verfasst: Dienstag 20. Januar 2009, 11:18
von Dr.Miles
Pekh hat geschrieben:Der Gebrauch von __del__ ist leider etwas problematisch, weil nicht genau gesagt werden kann, wann diese Methode intern aufgerufen wird.
Soweit ich weiß, doch immer dann irgendwann, wenn das instanzierte Objekt nicht mehr benötigt wird.
Vehikel.Anzahl ist ja das erste, was angelegt wird, wenn der Konstruktor aufgerufen wird, oder? Also muss Vehikel.Anzahl doch existieren?!
Pekh, es geht hierbei um eine Übung, damit ich das Klassenzeugs besser verstehe, deswegen hilft es mir in diesem Fall leider nicht, das problem anderst zu lösen, da ich dieses "Projekt" ja extra geschaffen habe, um solche probleme zu lösen, aber trotzdem danke für den Hinweis, hätte mir wahrscheinlich geholfen, wen es wirklich um dieses problem ginge.
gruß
Dr.Miles
Verfasst: Dienstag 20. Januar 2009, 11:38
von Pekh
So, ich habs rekonstruieren können:
Code: Alles auswählen
In [1]: class T(object):
...: Anzahl = 0
...: def __init__(self):
...: T.Anzahl += 1
...: def __del__(self):
...: T.Anzahl -= 1
...:
...:
# Mal testhalber zehn Ts erzeugen
In [2]: t_list = [T() for i in xrange(10)]
In [3]: T.Anzahl
Out[3]: 10
# weniger eins ...
In [4]: del(t_list[0])
# ... macht neun. Soweit richtig.
In [5]: T.Anzahl
Out[5]: 9
# Zusätzliche Referenz ...
In [6]: t1 = t_list[0]
# und noch mal löschen ...
In [7]: del(t_list[0])
# öh
In [8]: T.Anzahl
Out[8]: 9
# So, nun zum Problem: Ich binde mal den Namen der Klasse neu
In [9]: T = None
In [10]: del(t_list[0])
Exception exceptions.AttributeError: "'NoneType' object has no attribute
Anzahl'" in <bound method T.__del__ of <__main__.T object at
x851b62c>> ignored
Dein Problem ist scheinbar, daß irgendwann der Name 'Vehikel' oder 'Panzer' neu gebunden wird. Und zwar an einen NoneType. Somit funktionieren sämtliche Operationen auf dem ursprünglichen Klassenobjekt nicht mehr.
Edit: Kommentare und Zeilenumbruch eingefügt.
Verfasst: Dienstag 20. Januar 2009, 11:47
von Darii
Dr.Miles hat geschrieben:Pekh hat geschrieben:Der Gebrauch von __del__ ist leider etwas problematisch, weil nicht genau gesagt werden kann, wann diese Methode intern aufgerufen wird.
Soweit ich weiß, doch immer dann irgendwann, wenn das instanzierte Objekt nicht mehr benötigt wird.
Vehikel.Anzahl ist ja das erste, was angelegt wird, wenn der Konstruktor aufgerufen wird, oder? Also muss Vehikel.Anzahl doch existieren?!
Vehikel.Anzahl selbst existiert vermutlich noch, bloß der Name dafür nicht. Ich konnte dein Beispiel reproduzieren, wenn ich das als eigenes Script aufrufe. Das Problem ist, dass __del__ in diesem Fall aufgerufen wird, wenn der Interpreter gerade beendet wird. Und dieser Zustand ist recht undefiniert. Anscheinend wurde Vehikel schon neu an None gebunden(warum auch immer). Benutz einfach nicht __del__ dann hast du auch keine derartigen Probleme.
Ehrlich gesagt erschließt sich mir der Sinn von __del__ auch nicht so ganz.
Verfasst: Dienstag 20. Januar 2009, 12:37
von Dr.Miles
Darii hat geschrieben:Ehrlich gesagt erschließt sich mir der Sinn von __del__ auch nicht so ganz.
Ich lerne gerade OOP und das ist eigtl. ein beispiel aus A byte of python.
Code: Alles auswählen
def __del__(self):
'''Ich sterbe.'''
print '%s verabschiedet sich.' % self.name
Person.bevoelkerung -= 1
if Person.bevoelkerung == 0:
print 'Ich bin der letzte.'
else:
print 'Es gibt noch %d Leute.' % Person.bevoelkerung
davon habe ich mir das abgeschaut, das komplette beispiel ist unter
http://abop-german.berlios.de/read/clas ... -vars.html
Also soll ich mir einfach merken:
__del__ = böse ?
Verfasst: Dienstag 20. Januar 2009, 13:00
von Darii
Die Beschreibung von __del__ in ABOP ist auch nicht ganz korrekt. Es ist nicht nur nicht garantiert wann die Funktion aufgerufen wird, es ist noch nichteinmal garantiert *ob* sie aufgerufen wird. In der
Doku steht bei der Warnung zu __del__ auch genau dein Problem beschrieben.
Vergiss am besten, dass es __del__ gibt.
Also, when __del__() is invoked in response to a module being deleted (e.g., when execution of the program is done), other globals referenced by the __del__() method may already have been deleted. For this reason, __del__() methods should do the absolute minimum needed to maintain external invariants.
Verfasst: Dienstag 20. Januar 2009, 13:11
von Leonidas
Wenn man also unbedingt die Anzahl der Instanzen haben will, was meistens sowieso wenig sinnvoll ist, da man nicht jede Instanz unbedingt mitzählen will, dann kann man eine Liste mit Weakrefs vorhalten. Da gibts im Forum irgendwo ein Beispiel dafür.
Verfasst: Dienstag 20. Januar 2009, 16:11
von derdon
Gibt es auch ein Beispiel für eine *sinnvolle* Anwendung von __del__? Ich suche genauso wie Darli danach.
Verfasst: Dienstag 20. Januar 2009, 20:24
von BlackJack
Nein gibt's nicht.

Verfasst: Dienstag 20. Januar 2009, 20:29
von Birne94
vielleicht um bsp bei etwas wie einer Datei-Klasse.
Denn wenn zB eine Funktion beendet wird, dann wird hja meiner Meinung nach auch jedes Objekt gelöscht und (falls vorhanden) __del__ aufgerufen.
Dann könnte man noch das File-Objekt zB schließen etc...
Korrigiert mich, falls ich falsch liege...
Verfasst: Dienstag 20. Januar 2009, 20:31
von Darii
Warum hat unser altehrwürdiger BDFL __del__ dann überhaupt eingeführt?
Birne94 hat geschrieben:vielleicht um bsp bei etwas wie einer Datei-Klasse.
Denn wenn zB eine Funktion beendet wird, dann wird hja meiner Meinung nach auch jedes Objekt gelöscht und (falls vorhanden) __del__ aufgerufen.
Dann könnte man noch das File-Objekt zB schließen etc...
Bloß nicht. Wie gesagt der Aufruf von __del__ ist nicht garantiert, weder ob und wann.
Verfasst: Dienstag 20. Januar 2009, 21:06
von Leonidas
Birne94 hat geschrieben:Dann könnte man noch das File-Objekt zB schließen etc...
Dafür gibt es ``close()`` und die Context-Manager für das ``with``-Statement.
Verfasst: Dienstag 20. Januar 2009, 21:09
von BlackJack
@darii: Interessante Frage. Noch eine wäre warum sie bei Java den gleichen Fehler gemacht haben.

Verfasst: Dienstag 20. Januar 2009, 21:11
von str1442
http://de.wikipedia.org/wiki/Finalisierung
Unter Finalisierung. Listet genau die Probleme von __del__ auf. Warum diese Probleme derart global zu sein scheinen erklärt sich damit aber nicht.
Verfasst: Dienstag 20. Januar 2009, 21:12
von Birne94
@Leonidas
sicher, aber falls ein noch nicht so erfahrener Programmierer vergisst, das objekt zu schließen

Verfasst: Dienstag 20. Januar 2009, 21:13
von BlackVivi
Bestimmt gibts bei der low level Programmierung von der Python Standardlib wirklich ein paar Fälle, wo etwas passieren soll, wenn der GC etwas einsammelt. Nicht wenn es nicht mehr referenziert wird und so... Sondern einfach nur, wenn der GC es zerschrottet.
Das halte ich für.. sehr wahrscheinlich. Mal durchgucken, würd ich mal sagen =D
Verfasst: Dienstag 20. Januar 2009, 21:17
von derdon
An Birkendfeld: Kannst du uns als Developer etwas dazu sagen? Warum hat Guido __del__ implementiert, obwohl in der Doku davor gewarnt wird, es einzusetzen? Wusste man es früher einfach nicht besser?

Kennst du ein konkretes Beispiel, bei dem der Einsatz von __del__ Sinn ergibt?