Lässt sich eine vererbte Methode erweitern?
Hallo,
wenn Klasse B von Klasse A abgeleitet ist, gibt es dann einen Weg, eine Methode aus Klasse A nicht zu überschreiben sondern zu erweitern.
Anderst gesagt: Wenn die Methode ausgeführt wurde noch weitere Anweisungen bzw. eine weitere Methode auszuführen?
mutetella
wenn Klasse B von Klasse A abgeleitet ist, gibt es dann einen Weg, eine Methode aus Klasse A nicht zu überschreiben sondern zu erweitern.
Anderst gesagt: Wenn die Methode ausgeführt wurde noch weitere Anweisungen bzw. eine weitere Methode auszuführen?
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
Nicht im Python-Objekt-Modell. Du kannst aber die Methode ueberschreiben und in der Ueberschreibenden explizit die Ueberschriebene aufrufen.
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
Diesen Fall solltest du am besten in der Elternklasse behandeln:
`bar` ist hier die optionale Erweiterung.
Code: Alles auswählen
>>> class Spam(object):
... def foo(self):
... print "foo"
... self.bar()
... print "baz"
... def bar(self):
... pass
...
>>> class Eggs(Spam):
... def bar(self):
... print "bar"
...
>>> spam = Spam()
>>> eggs = Eggs()
>>> spam.foo()
foo
baz
>>> eggs.foo()
foo
bar
baz
Das Leben ist wie ein Tennisball.
@EyDu:
Das geht allerdings nur dann, wenn ich die Elternklasse auch verändern kann. Wenn ich z. B. von 'list' oder 'dict' erbe und die Methodennamen in der Kindklasse unverändert bleiben sollen, kann ich das so nicht machen...
@DasIch:
Um die Methode zu ersetzen müsste ich allerdings wissen, was die Elternmethode genau macht.
@cofi:
Genau so stelle ich mir das vor. Ich hatte nur bis gerade eben keine Vorstellung, wie ich das Original der überschriebenen Methode aufrufen kann.
Bin gerade auf dieses Beispiel zur Verwendung von 'super()' gestoßen.
Damit kann ich dann so Zeugs machen wie:
Ich verstehe allerdings noch nicht, weshalb es nicht heißen muss...
mutetella
Das geht allerdings nur dann, wenn ich die Elternklasse auch verändern kann. Wenn ich z. B. von 'list' oder 'dict' erbe und die Methodennamen in der Kindklasse unverändert bleiben sollen, kann ich das so nicht machen...
@DasIch:
Um die Methode zu ersetzen müsste ich allerdings wissen, was die Elternmethode genau macht.
@cofi:
Genau so stelle ich mir das vor. Ich hatte nur bis gerade eben keine Vorstellung, wie ich das Original der überschriebenen Methode aufrufen kann.
Bin gerade auf dieses Beispiel zur Verwendung von 'super()' gestoßen.
Damit kann ich dann so Zeugs machen wie:
Code: Alles auswählen
class List_(list):
def __init__(self, iterable):
list.__init__(iterable)
def append(self, item):
print 'Make some stuff before...'
super(List_, self).append(item)
print '... and make others after it!'
Code: Alles auswählen
super(list, self).append(item)
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
Ok, schaun wir uns doch mal an, was das bedeuten koennte.mutetella hat geschrieben:Ich verstehe allerdings noch nicht, weshalb es nichtheißen muss...Code: Alles auswählen
super(list, self).append(item)
Du gibst die Elternklasse an, deren Methode du haben moechtest dazu die Instanz und rufst auf dem Rueckgabewert eine Methode auf.
Welchen Unterschied sollte das zu `list.append(self, item)` haben? Und wie sollte sich aus einer Elternklasse die richtige Elternklasse bestimmen lassen?
Nein, man benoetigt die Klasse, von der man eine Elternklasse benoetigt.
Die Syntax ist allerdings reichlich gewoehnungsbeduerftig und man hat sich in Python 3 gluecklicherweise darum gekuemmert. Vergleiche http://docs.python.org/py3k/library/fun ... html#super mit http://docs.python.org/library/functions.html#super
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
@cofi:
Sorry, ich hab's echt versucht, aber ich verstehe Deine Erklärung nicht...
Warum als erstes Argument nicht die Elternklasse, deren Methode ich ja in Verbindung mit der Instanz (zweites Argument) aufrufen (Rückgabewert) möchte?
mutetella
Sorry, ich hab's echt versucht, aber ich verstehe Deine Erklärung nicht...
Eben. Weshalb also muss ich 'super()' als erstes Argument die Kindklasse und als zweites Argument dann die Instanz, die ja aus der Kindklasse hervorgeht, übergeben?cofi hat geschrieben:Du gibst die Elternklasse an, deren Methode du haben moechtest dazu die Instanz und rufst auf dem Rueckgabewert eine Methode auf.
Warum als erstes Argument nicht die Elternklasse, deren Methode ich ja in Verbindung mit der Instanz (zweites Argument) aufrufen (Rückgabewert) möchte?
Na eben den, dass in der Python 2-Variante der Aufruf nicht 'list.append(self, item)' sondern 'List_.append(self, item)' bedeutet. Und genau das finde ich merkwürdig.cofi hat geschrieben:Welchen Unterschied sollte das zu `list.append(self, item)` haben?
Indem ich die eine, wahre Elternklasse angebe? Und nicht auf eines der Kinder zurückgreife?cofi hat geschrieben:Und wie sollte sich aus einer Elternklasse die richtige Elternklasse bestimmen lassen?
Meinst Du dasselbe wie ich?cofi hat geschrieben:Die Syntax ist allerdings reichlich gewoehnungsbeduerftig ...
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
Ganz einfach: nehmen wir mal an, du hast Klassen A & C, C leitet von A ab. Jetzt waere Python so, wie du es beschreibst - man wuerde in C.foo A.foo aufrufen, indem man sagtmutetella hat geschrieben:@cofi:
Weshalb also muss ich 'super()' als erstes Argument die Kindklasse und als zweites Argument dann die Instanz, die ja aus der Kindklasse hervorgeht, übergeben?
Warum als erstes Argument nicht die Elternklasse, deren Methode ich ja in Verbindung mit der Instanz (zweites Argument) aufrufen (Rückgabewert) möchte?
super(A, self).foo()
Und jetzt kommst du auf die Idee, ein B einzufuerhen, das foo ueberlaedt, und davon leitet jetzt dein C zusaetzlich ab. Und jetzt steht da in deinem Code, man soll aber bitteschoen von A das foo aufrufen.
Das ist der Grund. super liefert die naechste Klasse in der sogenannten Method-Resolution-Order der *aktuellen* Klasse. Nicht von irgendeiner Klasse weiter oben in der Typhierarchie.
@mutetella: Die *eine, wahre* Elternklasse gibt es nicht. Jedenfalls nicht wenn man nicht nur eine Elternklasse hat.
Du könntest von `super()` auch einfach die Finger lassen. Lies Dir mal durch wie `super()` funktioniert und welche Einschränkungen das mit sich bringt: http://fuhm.net/super-harmful/
Du könntest von `super()` auch einfach die Finger lassen. Lies Dir mal durch wie `super()` funktioniert und welche Einschränkungen das mit sich bringt: http://fuhm.net/super-harmful/
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
Wenn du das tust, welchen Sinn hat dann der `super`-Aufruf? `super` ist dazu da, die _richtige_ Elternklasse auszuwählen.mutetella hat geschrieben:Eben. Weshalb also muss ich 'super()' als erstes Argument die Kindklasse und als zweites Argument dann die Instanz, die ja aus der Kindklasse hervorgeht, übergeben?cofi hat geschrieben:Du gibst die Elternklasse an, deren Methode du haben moechtest dazu die Instanz und rufst auf dem Rueckgabewert eine Methode auf.
Warum als erstes Argument nicht die Elternklasse, deren Methode ich ja in Verbindung mit der Instanz (zweites Argument) aufrufen (Rückgabewert) möchte?
Nehmen wir mal an wir haben ein `class A (B, C, D): ..` gebe ich jetzt dem `super` Aufruf nur ein `B` an, schneide ich 2 Drittel der nötigen Informationen ab.
`super` tut einfach etwas anderes als du denkst.
Die Instanz der Kindklasse ist nur nötig, damit am Ende ein Instanzobjekt rausfällt.
Na eben den, dass in der Python 2-Variante der Aufruf nicht 'list.append(self, item)' sondern 'List_.append(self, item)' bedeutet. Und genau das finde ich merkwürdig.[/quote]cofi hat geschrieben:Welchen Unterschied sollte das zu `list.append(self, item)` haben?
Nein eben nicht, würde da ein `List_.append` rausfallen hätten wir eine Endlosrekursion.
Neben der Tatsache, dass es nicht nur eine gibt: Wenn ich die schon angebe warum sollte ich sie noch bestimmen?mutetella hat geschrieben:Indem ich die eine, wahre Elternklasse angebe? Und nicht auf eines der Kinder zurückgreife?cofi hat geschrieben:Und wie sollte sich aus einer Elternklasse die richtige Elternklasse bestimmen lassen?
Meinst Du dasselbe wie ich?[/quote]cofi hat geschrieben:Die Syntax ist allerdings reichlich gewoehnungsbeduerftig ...
Nein ich denke nicht, für mich ist sie nicht "falsch" sondern eher umständlich.
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
Ok, ich beginne langsam zu verstehen, vielen Dank für Eure Mühe!!
Ich frage mich allerdings, weshalb es 'super()' überhaupt gibt, wenn doch ein 'SuperClass.method(self, arg)' direkt zum Ziel führt?
Folgende Aussage aus BlackJack's Link ist mir dabei nicht ganz klar:
mutetella
Ich frage mich allerdings, weshalb es 'super()' überhaupt gibt, wenn doch ein 'SuperClass.method(self, arg)' direkt zum Ziel führt?
Folgende Aussage aus BlackJack's Link ist mir dabei nicht ganz klar:
Was ist hier unter 'rautenförmiger (??) Vererbung' zu verstehen?"The only situation in which super() can actually be helpful is when you have diamond inheritance."
siehe hier
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit )
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
`super` gibt es, weil Mehrfachvererbung die Sache etwas komplizierter macht.
Zeichne dir mal ein Diagramm, wer von dem erbt, wenns dir auf einmal bayrisch wird hast du keinen Fehler gemacht
Code: Alles auswählen
class A():
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
Noe, du begreifst es offensichtlich immer noch nicht. Vielleicht hilft ja etwas Code, wo die Worte nicht ausreichen:mutetella hat geschrieben:Ok, ich beginne langsam zu verstehen, vielen Dank für Eure Mühe!!
Ich frage mich allerdings, weshalb es 'super()' überhaupt gibt, wenn doch ein 'SuperClass.method(self, arg)' direkt zum Ziel führt?
Code: Alles auswählen
class A(object):
def __init__(self):
super(A, self).__init__()
print "A.__init__"
class B(A):
def __init__(self):
super(B, self).__init__()
print "B.__init__"
class C(A):
def __init__(self):
super(C, self).__init__()
print "C.__init__"
class D(B, C):
def __init__(self):
# hier mal gaaaaaanz genau hinschauen
# und die Anzahl der Aufrufe im Code
# versus die Anzahl der ausgegebenen vergleichen
super(D, self).__init__()
print "D.__init__"
D()
Also ich glaub das ist ungefähr das gleiche,was ihr die ganze zeit besprecht, aber geht das nicht auch so:
So hab ich das immer gemacht
Code: Alles auswählen
class Mutter():
def hello(self,text):
print(text)
class Tochter(Mutter):
def __init__(self):
self.hello_ur=Mutter.hello
def hello(self,text):
self.hello_ur("dummy","none")
print(text)
a=Tochter()
a.hello("uhii")
Das sieht schwer umwegig aus. Zudem glaube ich nicht, dass dieser Code das tut, was du möchtest.Newcomer hat geschrieben:So hab ich das immer gemacht
Von welcher Python-Version redest du eigentlich? Ich nehme an Python 3, da du nicht von object erben lässt. Korrekt?
@Newcomer
Und was ist daran in irgendeiner Art von Vorteil gegenueber wahlweise super? Beziehungsweise
wenn man nicht super verwenden mag oder kann?
Ich kann auf jedenfall schonmal aufzaehlen, warum es *nicht* besser ist:
- mehr nutzloser code, ich kann mir ja zB das __init__ sparen in Tochter
- eine Instanzvariable weniger - weniger Zustand ist *immer* besser.
- Man "macht" es halt so nicht, ist un-pythonisch, das Idiom ist ja zB auch und gerade im Konstruktor
wenn man schon auf super verzichtet.
Und was ist daran in irgendeiner Art von Vorteil gegenueber wahlweise super? Beziehungsweise
Code: Alles auswählen
class Mutter():
def hello(self,text):
print(text)
class Tochter(Mutter):
def hello(self,text):
Mutter.hello(self, "dummy")
print(text)
Ich kann auf jedenfall schonmal aufzaehlen, warum es *nicht* besser ist:
- mehr nutzloser code, ich kann mir ja zB das __init__ sparen in Tochter
- eine Instanzvariable weniger - weniger Zustand ist *immer* besser.
- Man "macht" es halt so nicht, ist un-pythonisch, das Idiom ist ja zB auch und gerade im Konstruktor
Code: Alles auswählen
def __init__(self):
SuperKlasse.__init__(self)
Dann sollte man allerdings auch einheitlich im kompletten Projekt dabeibleiben. Diese klassische Art und die Verwendung von super innerhalb einer Vererbungshierarchie beißen sich ziemlich böse.deets hat geschrieben:wenn man schon auf super verzichtet.Code: Alles auswählen
def __init__(self): SuperKlasse.__init__(self)
Ich persönlich verwende durchgängig super().
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
@Newcome: Nein, das ist absolut kaputt.
Siehe hier:
Siehe hier:
Code: Alles auswählen
In [6]: %edit tmp/foo.py
Editing... > emacsclient -nw +0 tmp/foo.py
done. Executing edited code...
In [7]: t = Tochter()
In [8]: t.hello("there")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/cofi/<ipython console> in <module>()
/home/cofi/tmp/foo.py in hello(self, text)
10 self.hello_ur = Mutter.hello
11
12 def hello(self, text):
---> 13 self.hello_ur("dummy", "none")
14 print text
TypeError: unbound method hello() must be called with Mutter instance as first argument (got str instance instead)
Code: Alles auswählen
# tmp/foo.py
class Mutter(object):
def __init__(self):
self.greeter = "Hello %s"
def hello(self, text):
print self.greeter % text
class Tochter(Mutter):
def __init__(self):
self.hello_ur = Mutter.hello
def hello(self, text):
self.hello_ur("dummy", "none")
print text
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
bei mir funktioniert das einwandfrei:
Code: Alles auswählen
Python 3.2.1 (default, Jul 10 2011, 20:02:51) [MSC v.1500 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
>>> t=Tochter()
>>> t.hello("there")
none
there
>>>