Seite 1 von 1

Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4 ...)

Verfasst: Samstag 28. Mai 2011, 17:55
von moe.pub
Guten Tag meine Damen und Herren,

ich stehe gerade vor einem kleinen Problem mit meiner Vererbungshierarchie und finde einfach keine ellegante Loesung.
Als beispiel habe ich mal folgende Klassenhierarchie erstellt, die das Problem verdeutlichen soll:

Code: Alles auswählen

class A(object):
	def __init__(self, param):
		print 'A'

class B(A):
	def __init__(self, param1, param2):
#		super(self.__class__, self).__init__(param1)
#		<super: <class 'B'>, <B object>>
#		print super(self.__class__, self)
		print 'B'
		

class C(B):
	def __init__(self, param1, param2):
#		super(self.__class__, self).__init__(param1, param2)
#		<super: <class 'C'>, <C object>
#		print super(self.__class__, self)
		print 'C()'

class D(C):
	def __init__(self, param1, param2):
#		super(self.__class__, self).__init__(param1, param2)
		print 'D()'
Jetzt moechte ich in jedem Constructor natuerlich den Constructor der Basisklasse aufrufen, will heissen, wenn ich eine Instanz von D anlege, dann soll folgende Ausgabe produziert werden:

A
B
C
D

Nun habe ich die Funktion super() gefunden, die wie es mir scheint, allerdings fuer diese Aufgabe nicht wirklich geeignet ist.
Wenn ich in jedem der Constructoren "super(self.__class__, self).__init__(param1, param2)" einfuege, so gibt es ab der Klasse C Probleme:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
File "<stdin>", line 3, in __init__
TypeError: __init__() takes exactly 3 arguments (2 given),

und bei Klasse D geht gar nicht's mehr. Nun habe ich nachgelesen und mir scheint es, dass super nur eine bestimmte Klasse aus der Vererbungshierarchy herausnimmt, und dann den Methodenaufruf an die entsprechende Superklasse weiterleitet.
In der Theorie klingt das ganz gut, nur scheint das irgendwie nicht zu funktionieren.

Ich hoffe mir kann hier weitergeholfen werden, denn ich moechte nicht zurueck zu der Methode, wo die Superklasse im Constructor explizit aufscheint.

Daher, bitte um Hilfe ...

Gruesse,
MoE

Re: Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4

Verfasst: Samstag 28. Mai 2011, 18:39
von Tompazi
Dein Fehler liegt beim Aufbau der Klassen.
Ich versteh zwar nicht was du machen willst aber schau dir mal das Klassensystem von Python an

Code: Alles auswählen

class A(object):
        def __init__(self):
                print 'A'

class B(object):
        def __init__(self):
                print 'B'
                A()

class C(object):
        def __init__(self):
                print 'C'
                B()

class D(object):
        def __init__(self):
                print 'D'
                C()
D()
MfG Tompazi

Re: Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4

Verfasst: Samstag 28. Mai 2011, 19:05
von moe.pub
Aber so sind das nur einzelne Klassen, die nicht voneinander ableiten.
Jede Klasse soll von der anderen ableiten und jeweils im Konstruktor den der Superklasse aufrufen (ohne dass der Name der Superklasse explizit zum Aufruf des Superkonstruktors verwendet wird). Es soll eine Vererbungshierarchie entstehen.

Die Vererbung wird benötigt, um generisch Zugriff auf sämtliche Operatoren zu haben.

Re: Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4

Verfasst: Samstag 28. Mai 2011, 19:18
von Pekh

Code: Alles auswählen

class A(object):
	def __init__(self, param):
		print 'A'

class B(A):
	def __init__(self, param1, param2):
		A.__init__(self, param1, param2)
		print 'B'
		

class C(B):
	def __init__(self, param1, param2):
                B.__init__(self, param1, param2)
		print 'C()'

class D(C):
	def __init__(self, param1, param2):
		C.__init__(self, param1, param2)
		print 'D()'
Sollte das gewünschte Ergebnis zeitigen. Den Namen der direkten Vaterklasse kennst und brauchst du auf jeden Fall, also kannst du ihn doch auch in der init verwenden, oder?

Edit: Parameter vergessen.

Re: Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4

Verfasst: Samstag 28. Mai 2011, 19:30
von moe.pub
Aus Sicht eines Softwareentwickler ist das aber nicht schön. Das muss doch irgendwie sonst gehn ...

Dein Vorschlag ist mir natürlich bekannt, halte das ganze aber für nicht sauber.

Re: Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4

Verfasst: Samstag 28. Mai 2011, 19:37
von BlackJack
@moe.pub: So macht man das aber.

Warum `super()` bei Dir so nicht funktioniert kannst Du hier nachlesen: http://fuhm.net/super-harmful/

Ich find's ziemlich unbenutzbar und verwirrend. Und da ich keine Mehrfachvererbung verwende, tue ich mir das nicht an.

Re: Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4

Verfasst: Samstag 28. Mai 2011, 19:40
von Pekh
Ich bin Software-Entwickler. Was ist daran nicht schön? Daß du ihm sagen mußt, wo er die Methode zu suchen hat? Es gibt Fälle, in denen der Konstruktor (ist __init__ ja eigentlich nicht, aber das lassen wir mal außen vor) der Vaterklasse gar nicht aufgerufen werden soll. Oder halt erst nachdem der "neue" Code durch ist. Insofern kann man den Konstruktoraufruf der Vaterklasse nicht automatisieren. Und ob du nun 'super.__init__' oder 'A.__init__' schreibst ist doch eigentlich gehüpft wie gesprungen. An der Stelle 'classX(A)' brauchst du die Information doch ohnehin.

Re: Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4

Verfasst: Samstag 28. Mai 2011, 20:59
von moe.pub
@BlackJack: Mehrfachvererbung ist was anderes

@Pekh
Ich kenn jetzt keine andere Sprache, wo eine Methode der Superklasse so kompliziert aufgerufen werden muss.
(OCamel hat ich noch nie die Objektorientierten Features benutzt, aber der Sprache traue ich das zu)

Warum A.__init__(self, param1, param2) mir nicht zusagt hat mehrere Gruende. Es erinnert mich sehr viel mehr an einen Aufruf einer statischen Methode. Ich denke, wenn ich den Code in einem Jahr wieder durchlese, ... Und ausserdem, wenn ich so an refactoring denke, naja, wie gesagt, es gibt mehrere Gruende warum mir das Konzept nicht gefaellt.

Und das der Superkonstruktor nicht oder nur nach einigen Initialisierungsmassnahmen aufgerufen werden soll ....
Ich wuerde so etwas in meinem ganzen Leben nicht machen. Da wuerde ich eher die Klassenhierarchie umstellen oder gewisse Sachen deligieren.

Aber ich werde mich der Sprache wohl fuegen muessen, das Projekt ist mittlerweile schon so fortgeschritten dass ein Umstieg auf eine andere Sprache zu viel Zeit verursachen wuerde.

Re: Vererbung: Superconstructor aufrufen ... (Level 2, 3, 4

Verfasst: Sonntag 29. Mai 2011, 00:26
von BlackJack
@moe.pub: Mehrfachvererbung ist etwas anderes als *was*? Dass Du da keine hast ist mir klar — genau deswegen kannst Du ja auf `super()` verzichten. Du würdest es ja aber anscheinend trotzdem gerne verwenden. Dann musst Du aber auch mit den Eigenarten davon leben. Und verstehen warum es in Deinem Beispiel nicht funktioniert.

Was ist an dem Aufruf so kompliziert? Du rufst die Funktion auf der Elternklasse doch ziemlich einfach und direkt auf. Die Elternklasse musst Du angeben, weil es davon mehrere geben kann und es sonst nicht eindeutig wäre. Dann folgt der Funktionsname und die Argumente. Du rufst halt die Funktion auf und keine Methode, denn auf der Klasse sind die Attribute noch keine gebundenen Methoden. ``A.f(x, 42)`` ist ja das selbe wie ``x.f(42)`` wenn `x` vom Typ `A` ist. Den Typ muss man wie gesagt angeben, und ansonsten ist es nicht komplizierter.