Lässt sich eine vererbte Methode erweitern?

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

/me hat geschrieben: 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.

Ich persönlich verwende durchgängig super().
Jein. Fuer Konstruktoren - ich natuerlich auch. Wobei man da gerne Fehler macht, weil man in zwei Basisklassen, die direkt von object erben oft vergisst.

Aber bei normalen Methoden ist die Sache nicht gaaanz so einfach - denn da erwarte ich ja genau einen Rueckgabewert, und im Fall eines Diamondshape kommt's auf die MRO an- da gehe ich dann doch gelegentlich hin, und mach's explizit.

Ganz ehrlicherweise ist aber das ganze Problem eh eher gering, das ich mal mehr als 1 Ableitungshierarchie habe kommt *so* selten vor, und Mehrfachvererbung eigentlich immer nur als Pseudo-Mixins.

Code: Alles auswählen



class B(object):

    def __init__(self):
        #super(B, self).__init__()
        print "B.__init__"


    def foo(self):
        return "B"

class C(object):

    def __init__(self):
        #super(C, self).__init__()
        print "C.__init__"


    def foo(self):
        return "C"


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__"



    def foo(self):
        return super(D, self).foo()

class E(C, B):

    def __init__(self):
        # hier mal gaaaaaanz genau hinschauen
        # und die Anzahl der Aufrufe im Code
        # versus die Anzahl der ausgegebenen vergleichen
        super(E, self).__init__()
        print "E.__init__"



    def foo(self):
        return super(E, self).foo()

d = D()
print d.foo()

e = E()
print e.foo()
deets

Newcomer hat geschrieben:Mir macht das nur spaß, deshalb reicht es für meine verhältnisse
Bloss weil man nicht Installateur werden will, muss man sich mit einer Bohrmaschine ja noch lange nicht in den Fuss bohren, oder? Sich gutes arbeiten anzugewoehnen ist immer ... gut. Dass du es bisher so gemacht hast ist ja ok. Sich aber dem dazulernen zu verweigern, finde ich spannend.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Newcomer hat geschrieben:bei mir funktioniert das einwandfrei:
Dein Code ja, weil `Mutter.hello` bei dir keine wirkliche Methode ist und `self` nicht nutzt. Eine Methode benoetigt als erstes Argument aber _immer_ ein Instanz-Objekt und keine String namens "dummy".
`Tochter.hello` sollte also `self.hello_ur(self, "none")` nutzen.

In Python3 gibt das eine andere Fehlermeldung, hat aber denselben Grund:

Code: Alles auswählen

%> python3 -i tmp/foo.py
>>> t = Tochter()
>>> t.hello("there")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tmp/foo.py", line 13, in hello
    self.hello_ur("dummy", "none")
  File "tmp/foo.py", line 6, in hello
    print(self.greeter % text)
AttributeError: 'str' object has no attribute 'greeter'
>>>
Newcomer
User
Beiträge: 131
Registriert: Sonntag 15. Mai 2011, 20:41

@cofi Hä das versteh ich nicht, bei mir funktionierts auch mit self, is aber auch egal. P.s. Ist dein Bild aus conway´s game of life?
@deets
deets hat geschrieben:
Newcomer hat geschrieben:Mir macht das nur spaß, deshalb reicht es für meine verhältnisse
Bloss weil man nicht Installateur werden will, muss man sich mit einer Bohrmaschine ja noch lange nicht in den Fuss bohren, oder? Sich gutes arbeiten anzugewoehnen ist immer ... gut. Dass du es bisher so gemacht hast ist ja ok. Sich aber dem dazulernen zu verweigern, finde ich spannend.
Ich hab nicht behauptet, dass ich nichts gelernt habe oder lernen wollte. Hab mir die bisherigen beiträge alle brav durchgelesen und vieles neues dazugelernt (super() bsp). Dein Vergleich mit dem Installateur zieht nicht so ganz, denn unter berücksichtigung einer Verletzung am Fuß müsste mindestens mein Prozesser in die Luft gehen, wenn ich ihn zu sehr mit schlechtem code ärgere (-; 8) 8) :D
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ok, ich hab' jetzt mal a bisl rumgebastelt und -gespielt und bin zu folgender Erkenntnis gelangt :) :
  • Durch den Einsatz von 'super()' wird bei Mehrfachvererbung in der korrekten Reihenfolge und Anzahl instanziiert:
    Erst mal die Mama, danach, in umgekehrter Reihenfolge die Klassen, von denen direkt geerbt wird.
  • Dazu muss aber konsequent in allen beteiligten Klassen 'super()' verwendet werden.
  • Bei einfacher Vererbung kann und sollte auf 'super()' verzichtet werden, siehe BlackJack's Link.
Stimmt das so in etwa?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

mutetella hat geschrieben:
  • Durch den Einsatz von 'super()' wird bei Mehrfachvererbung in der korrekten Reihenfolge und Anzahl instanziiert:
    Erst mal die Mama, danach, in umgekehrter Reihenfolge die Klassen, von denen direkt geerbt wird.
Es ist leider ein ganzes Stueck komplizierter. Die Details gibts hier: http://www.python.org/download/releases/2.3/mro/

Oh und dann schiess ich nochmal gegen `super` ist boese: http://rhettinger.wordpress.com/2011/05 ... red-super/
BlackJack

@cofi: Hettinger ist ja schon irgendwo ein Held, aber bei dem Artikel habe ich nur den Kopf geschüttelt. `super()` ist gar nicht so schlimm, wenn man bei jeder Methode sowohl in der Signatur als auch beim Aufruf ein ``**kwds`` anhängt und nette kleine Adapterklassen für alles schreibt was nicht `super()` verwendet. :?

Ich sehe zwei Probleme bei `super()`.

1. Man kann herkömmlichen und `super()`-Code nicht mischen. Das heisst ein Umstieg ist mit umschreiben von vielen Klassen und mit Adapterklassen für Code den man nicht unter seiner Kontrolle hat, verbunden. Da ich Mehrfachvererbung nur für Mixin-Klassen verwende, sehe ich dabei für mich aber überhaupt keinen Vorteil `super()` zu verwenden und mir die zusätzliche Arbeit zu machen. Und ich glaube nicht das ich damit alleine da stehe.

2. Vielleicht nur mein Problem, aber ich sehe das durchreichen von ``**kwds`` überall als ziemlich unschön an. Das riecht nach Boilerplate oder Hack und das die Sprache an der Stelle nicht ordentlich durchdacht ist. Beim Vorbild für die MRO gibt es das nicht, weil die Funktionssignatur bei Dylan in der gesamten Hierarchie tatsächlich fest sein muss.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ich hätte jetzt mal ein konkretes Beispiel:

Code: Alles auswählen

class DefaultList(list):
    def __init__(self, iterable=None, default=None):
        self._default = default or ()
        list.__init__(self, iterable or ())

    def remove(self, value):
        list.remove(self, value)
        self._is_empty()

    def pop(self, index):
        list.pop(self, index)
        self._is_empty()
   
    def __delitem__(self, index):
        list.__delitem__(self, index)
        self._is_empty()

    def __delslice__(self, start, stop):
        list.__delslice__(self, start, stop)
        self._is_empty()
 
    def _is_empty(self):
        if len(self) <= 0:
            self[:] = self._default
Sehe ich das richtig, dass hier der explizite Aufruf von list-Methoden sinnvoller oder sogar richtiger als der Einsatz von 'super()' ist?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten