Seite 1 von 1

Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Freitag 24. September 2010, 21:56
von droptix
Habe Klasse `Man` mit Methode `speak`, die in der Subclass `ShoutingMan` überschrieben werden soll. Es gibt zusätzlich die Standard-Methode zum Sprechen `__default_speak`. Die brauche ich, um abfragen zu können, ob jemand anders als normal spricht, also ob `speak` überschrieben wurde. Daher setze ich in `Man.__init__` einfach `self.speak = self.__default_speak`.

Problem: in Subclasses wird eine Methode namens `speak` ignoriert, d.h. die überschreibt den in der Baseclass in `__init__` zugewiesenen Wert nicht. Ich kann mir derzeit nur behelfen, indem ich `__init__` re-definiere und manuell `speak` neu mittels einer Hilfsfunktion zuweise, siehe Code unten.

Wieso? Der Umweg über die Hilfsfunktion `yell` und die Re-Definition von `__init__` ist eigentlich unnötig und daher unschön. V.a. aber verstehe ich es nicht...

Code: Alles auswählen

class Man:
    def __init__(self):
        self.speak = self.__default_speak
    def __default_speak(self, text):
        return text
    def speaks_special(self):
        return not self.speak == self.__default_speak

class ShoutingMan(Man):
    def speak(self, text):
        return text.upper()

sman = Man()
print sman.speak("Hello")
# prints: Hello, `speak` seems not to be overwritten in class `ShoutingMan`
print sman.speaks_special()
# prints: False

class YellingMan(Man):
    def __init__(self):
        Man.__init__(self)
        self.speak = self.yell
    def yell(self, text):
        return text.upper()

yman = YellingMan()
print yman.speak("Hello")
# prints: HELLO, `speak` has been overwritten in class `YellingMan`
print yman.speaks_special()
# prints: True

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Freitag 24. September 2010, 22:12
von BlackJack
@droptix: `ShoutingMan` hat zwar eine eigene `speak()`-Methode, die wird aber im erstellten Exemplar wenn die `__init__()` ausgeführt wird, mit `self.__default_speak` verdeckt. Die `__init__()` von `Man` wird doch beim erstellen von `ShoutingMan` ausgeführt, wenn `ShoutingMan` keine eigene `__init__()` definiert.

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 06:59
von ntrunk
@droptix: Ergänzend zu der Erklärung von Blackjack möchte ich mal etwas provokant in den Raum werfen: Wozu willst du das eigentlich wissen? Ich hatte auch schon ähnliche Situationen, und es hat sich immer herausgestellt, dass die Ursache in einem suboptimalen Design des Klassenmodells lag. Wenn dabei dann ungefähr solcher Code herauskommt:

Code: Alles auswählen

class BaseClass:
[...]
    def tu_was(self):
        if self.was_overwritten('some_method'):
            self.tu_dies()
        else:
            self.tu_jenes()
dann wird das wahrscheinlich besser gelöst in einem Überschreiben von tu_jenes(). Überleg mal:
- wenn der Code in Man die Spezialfälle abhandeln soll, für was brauchst du dann überhaupt die abgeleitete Klasse?
- sobald du eine neue Klasse ableitest, musst du die Basisklasse verändern (und neu testen und alle bereits funktionierenden abgeleiteten Klassen ebenfalls...)!
Der Sinn des Überschreibens von Methoden liegt ja m.E. gerade darin, dass man den Code für die Basisklasse völlig von den abgeleiteten Klassen abkoppeln kann.

Gruß
Norbert

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 07:36
von Darii
droptix hat geschrieben:Habe Klasse `Man` mit Methode `speak`, die in der Subclass `ShoutingMan` überschrieben werden soll. Es gibt zusätzlich die Standard-Methode zum Sprechen `__default_speak`. Die brauche ich, um abfragen zu können, ob jemand anders als normal spricht, also ob `speak` überschrieben wurde. Daher setze ich in `Man.__init__` einfach `self.speak = self.__default_speak`.
Du kannst auch Zuweisungen in der Klassendefinition selbst machen:

Code: Alles auswählen

class Man(object):
    def __speak(): pass
    speak = __speak

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 08:51
von Dav1d
Darii hat geschrieben:Du kannst auch Zuweisungen in der Klassendefinition selbst machen:

Code: Alles auswählen

class Man(object):
    def __speak(): pass
    speak = __speak
Aber bitte ohne doppelte führende Unterstriche..

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 09:15
von BlackJack
Mal abgesehen davon, dass ich es wie ntrunk sehe und das wahrscheinlich gar nicht machen würde, täte ich es komplett ohne extra Methode. Man könnte einfach die "aktuelle" Methode mit der in `Man` vergleichen:

Code: Alles auswählen

class Man(object):
    def speak(self, text):
        return text
    
    def is_special_speaker(self):
        return self.__class__.speak != Man.speak


class ShoutingMan(Man):
    def speak(self, text):
        return text.upper()


def main():
    for man in [Man(), ShoutingMan()]:
        print man.speak('Hello')
        print man.is_special_speaker()

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 09:33
von Dav1d
Ich find das mit einem "property" schöner und passender:

Code: Alles auswählen

class Man(object):
    def speak(self, text):
        return text
   
    @property
    def is_special_speaker(self):
        return self.__class__.speak != Man.speak

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 09:36
von Darii
Dav1d hat geschrieben:
Darii hat geschrieben:Du kannst auch Zuweisungen in der Klassendefinition selbst machen:

Code: Alles auswählen

class Man(object):
    def __speak(): pass
    speak = __speak
Aber bitte ohne doppelte führende Unterstriche..
Weil? Genau für so einen Fall sind sie da, um versehentliches Überschreiben zu verhindern.

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 09:54
von Dav1d
Ich finde man sollte sie sogar überschreiben:

Code: Alles auswählen

class Man(object):
    def __init__(self):
        pass # was auch immer hier noch hin soll
    def speak(self, text):
        return text
    def speaks_special(self):
        return not self.__class__.speak == Man.speak

class ShoutingMan(Man):
    def __init__(self):
        Man.__init__(self)
    def speak(self, text):
        return text.upper()

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 11:07
von droptix
ntrunk hat geschrieben:@droptix: Ergänzend zu der Erklärung von Blackjack möchte ich mal etwas provokant in den Raum werfen: Wozu willst du das eigentlich wissen? Ich hatte auch schon ähnliche Situationen, und es hat sich immer herausgestellt, dass die Ursache in einem suboptimalen Design des Klassenmodells lag.
Ja, das kann gut sein, daher frag ich ja. Das hier gefällt mir ganz gut, darauf bin ich nicht gekommen:
BlackJack hat geschrieben:Mal abgesehen davon, dass ich es wie ntrunk sehe und das wahrscheinlich gar nicht machen würde, täte ich es komplett ohne extra Methode. Man könnte einfach die "aktuelle" Methode mit der in `Man` vergleichen:

Code: Alles auswählen

class Man(object):
    def speak(self, text):
        return text
    
    def is_special_speaker(self):
        return self.__class__.speak != Man.speak
@Dav1d: Was hat das mit dem @property auf sich? Ist das Python 3000?

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 11:16
von BlackJack
@droptix: Die `property()`-Funktion gibt es sein Python 2.2 und die Decorator-Syntax (@) seit Python 2.4 -- ist also beides schon recht "alt".

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 11:35
von Darii
Dav1d hat geschrieben:Ich finde man sollte sie sogar überschreiben:
Was meinst du? Was willst du überschreiben? Man.speak offensichtlich nicht. Ich auch nicht, deswegen __speak(bzw. __default_speak wie auch immer man das nennen möchte).

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 11:39
von Dav1d
Darii hat geschrieben:
Dav1d hat geschrieben:Ich finde man sollte sie sogar überschreiben:
Was meinst du? Was willst du überschreiben? Man.speak offensichtlich nicht. Ich auch nicht, deswegen __speak(bzw. __default_speak wie auch immer man das nennen möchte).
:?:

Ich überschreibe Man.speak mit ShoutingMan.speak

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 12:02
von Darii
Dav1d hat geschrieben:Ich überschreibe Man.speak mit ShoutingMan.speak
Ahhh… du überschreibst niemals Man.speak. Das ist doch der Punkt. Genausowenig wie self._Man__speak jemals überschrieben wird.

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 12:25
von BlackJack
@Darii: Also ich kenne das Neuimplementieren einer Methode in einer Unterklasse als "überschreiben". Und genau das tut Dav1d in seinem Beispiel.

Re: Verständnisfrage: Subclass überschreibt Methode nicht

Verfasst: Samstag 25. September 2010, 13:16
von Darii
BlackJack hat geschrieben:@Darii: Also ich kenne das Neuimplementieren einer Methode in einer Unterklasse als "überschreiben". Und genau das tut Dav1d in seinem Beispiel.
Ja ich weiß, das Wort ist leider doppelt belegt. ;) ich hatte jetzt aber kein Lust noch ewig weiterzuargumentieren. Dav1d hat jetzt immer noch nicht erklärt, warum keine __ zu verwenden sind. Sein Beispiel hat damit nunmal rein gar nichts zu tun.

Wenn man schon meint irgendjemanden verbessern zu müssen dann auch bitte mit Begründung und nicht nur son Halbsatz…