Vererbung / self

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.
Benutzeravatar
Dr.Miles
User
Beiträge: 38
Registriert: Montag 15. Dezember 2008, 08:33
Wohnort: Mannheim
Kontaktdaten:

Dienstag 20. Januar 2009, 08:04

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
www.i2p2.de <--- sehr interressantes Anonymisierungsprojekt.
www.schaeuble-wegtreten.de <--- Petition gegen Schäuble
Benutzeravatar
cofi
Moderator
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Dienstag 20. Januar 2009, 08:23

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.
Benutzeravatar
Dr.Miles
User
Beiträge: 38
Registriert: Montag 15. Dezember 2008, 08:33
Wohnort: Mannheim
Kontaktdaten:

Dienstag 20. Januar 2009, 09:09

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
www.i2p2.de <--- sehr interressantes Anonymisierungsprojekt.
www.schaeuble-wegtreten.de <--- Petition gegen Schäuble
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Dienstag 20. Januar 2009, 09:36

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.
Benutzeravatar
Dr.Miles
User
Beiträge: 38
Registriert: Montag 15. Dezember 2008, 08:33
Wohnort: Mannheim
Kontaktdaten:

Dienstag 20. Januar 2009, 11:18

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
www.i2p2.de <--- sehr interressantes Anonymisierungsprojekt.
www.schaeuble-wegtreten.de <--- Petition gegen Schäuble
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Dienstag 20. Januar 2009, 11:38

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.
Zuletzt geändert von Pekh am Dienstag 20. Januar 2009, 11:47, insgesamt 1-mal geändert.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Dienstag 20. Januar 2009, 11:47

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.
Benutzeravatar
Dr.Miles
User
Beiträge: 38
Registriert: Montag 15. Dezember 2008, 08:33
Wohnort: Mannheim
Kontaktdaten:

Dienstag 20. Januar 2009, 12:37

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 ?
www.i2p2.de <--- sehr interressantes Anonymisierungsprojekt.
www.schaeuble-wegtreten.de <--- Petition gegen Schäuble
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Dienstag 20. Januar 2009, 13:00

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.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 20. Januar 2009, 13:11

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.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Dienstag 20. Januar 2009, 16:11

Gibt es auch ein Beispiel für eine *sinnvolle* Anwendung von __del__? Ich suche genauso wie Darli danach.
Birne94
User
Beiträge: 90
Registriert: Freitag 28. November 2008, 15:18
Kontaktdaten:

Dienstag 20. Januar 2009, 20:29

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...
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Dienstag 20. Januar 2009, 20:31

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.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 20. Januar 2009, 21:06

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.
Antworten