Die Vererbung spielt in der objektorientierten Programmierung eine bedeutende Rolle. Ohne
Vererbung müsste zuerst eine übergeordnete Klasse instanziiert werden, um z.B. auf die öffentlichen Eigenschaften
(Attribute) dieser übergeordneten Klasse zugreifen und in einer nachfolgenden Klasse mit diesen arbeiten
zu können. Ebenso verhält es sich mit den Funktionalitäten von Methoden.
Zuerst ein Beispiel ohne Vererbung. Um mit den Attributen der Klasse "Säuger" in der Klasse "Mensch" arbeiten
zu können, wird zuerst die Klasse Säuger instanziiert, danach die Klasse Mensch und dabei der Klasse Mensch die
Werte der Attribute aus der Instanz "Säuger" übergeben.
Beispiel 1 (ohne Vererbung):
class Saeuger: def __init__(self): self.ordnung = "Primaten" self.familie = "Menschenaffen" self.spezies = "Mensch" class Mensch: def __init__(self, ordnung, familie, spezies): self.ordnung = ordnung self.familie = familie self.spezies = spezies def get_spezies(self): art_spezies = "Der {0} gehört im Tierreich ".format(self.spezies) art_ordnung = "zur Ordnung der {0} ".format(self.ordnung) art_familie = "und zur Familie der {0}.\n".format(self.familie) return "{0}{1}{2}".format(art_spezies, art_ordnung, art_familie) erste_instanz = Saeuger() zweite_instanz = Mensch(erste_instanz.ordnung, erste_instanz.familie, erste_instanz.spezies) print(zweite_instanz.get_spezies())
Eine andere Möglichkeit bestünde darin, eine Klasse in einer anderen zu instanziieren.
Von dieser Möglichkeit wird häufiger Gebrauch gemacht, als von der hier aufgezeigten Variante.
Nun drei Beispiele mit Vererbung. Damit eine abgeleitete Kinderklasse von einer übergeordneten Elternklasse erben
kann, muss der Bezeichner von der Elternklasse in Klammern hinter der Definition einer Kinderklasse notiert werden.
Beispiel 2 (mit Vererbung):
class Saeuger: def __init__(self): self.ordnung = "Primaten" self.familie = "Menschenaffen" self.spezies = "Mensch" class Mensch(Saeuger): def get_spezies(self): art_spezies = "Der {0} gehört im Tierreich ".format(self.spezies) art_ordnung = "zur Ordnung der {0} ".format(self.ordnung) art_familie = "und zur Familie der {0}.\n".format(self.familie) return "{0}{1}{2}".format(art_spezies, art_ordnung, art_familie) instanz = Mensch() print(instanz.get_spezies())
Das dritte Beispiel unterscheidet sich vom zweiten Beispiel lediglich dadurch, dass beim Instanziieren der Kinderklasse "Mensch" ein Wert für die Attribute-Eigenschaft "spezies" der Elternklasse "Saeuger" übergeben wird.
Beispiel 3 (mit Werteübergabe):
class Saeuger: def __init__(self, spezies_value = None): self.ordnung = "Primaten" self.familie = "Menschenaffen" self.spezies = spezies_value class Mensch(Saeuger): def get_spezies(self): art_spezies = "Der {0} gehört im Tierreich ".format(self.spezies) art_ordnung = "zur Ordnung der {0} ".format(self.ordnung) art_familie = "und zur Familie der {0}.\n".format(self.familie) return "{0}{1}{2}".format(art_spezies, art_ordnung, art_familie) instanz = Mensch("Mensch") print(instanz.get_spezies())
Beim vierten Beispiel wurde die Methode get_spezies() in die Elternklasse verschoben. Um in der erbenden Klasse Mensch auf diese Methode beim Instanziieren zugreifen zu können, wird diese mit der Methode get_art() in der Kinderklasse aufgerufen.
Beispiel 4 (mit Vererbung einer Methode):
class Saeuger: def __init__(self, spezies_value = None): self.ordnung = "Primaten" self.familie = "Menschenaffen" self.spezies = spezies_value def get_spezies(self): art_spezies = "Der {0} gehört im Tierreich ".format(self.spezies) art_ordnung = "zur Ordnung der {0} ".format(self.ordnung) art_familie = "und zur Familie der {0}.\n".format(self.familie) return "{0}{1}{2}".format(art_spezies, art_ordnung, art_familie) class Mensch(Saeuger): def get_art(self): return self.get_spezies() instanz = Mensch("Mensch") print(instanz.get_art())
Bei der Vererbung muss bedacht werden, dass die Vergabe von gleichnamigen Bezeichnern
beim Definieren von Methoden in einer vererbenden und in einer erbenden Klasse eine Überschreibung der geerbten
Methoden in der erbenden Klasse bewirkt. Von dieser Überschreibung in der erbenden Klasse ist auch die __init__
Methode nicht ausgeschlossen, insofern beide Klassen eine __init__ Methode besitzen. Um einer Überschreibung
entgegenzuwirken muss die __init__ Methode aus der Elternklasse in einer erbenden Klasse mit Parametern aufgerufen
werden, selbst wenn diese Parameter wie im ersten Beispiel nur als Platzhalter für die eigentlichen Argumente
dienen.
Nebenbei sei erwähnt, Parameter dienen der Übergabe von Werten, erst innerhalb einer Funktion oder Methode werden
Parameter und deren Werte als Argumente benutzt.
Beispiel 5 (mit Platzhaltern für Parameter):
class Saeuger: def __init__(self, ordnung, familie): self.ordnung = "Primaten" self.familie = "Menschenaffen" class Mensch(Saeuger): def __init__(self): self.spezies = "Mensch" Saeuger.__init__(self, "?", "?") def get_art(self): art_spezies = "Der {0} gehört im Tierreich ".format(self.spezies) art_ordnung = "zur Ordnung der {0} ".format(self.ordnung) art_familie = "und zur Familie der {0}.\n".format(self.familie) return "{0}{1}{2}".format(art_spezies, art_ordnung, art_familie) instanz = Mensch() print(instanz.get_art())
Beispiel 6 (mit der Übergabe von Werten):
class Saeuger: def __init__(self, value_ordnung, value_familie): self.ordnung = value_ordnung self.familie = value_familie def get_spezies(self): art_spezies = "Der {0} gehört im Tierreich ".format(self.spezies) art_ordnung = "zur Ordnung der {0} ".format(self.ordnung) art_familie = "und zur Familie der {0}.\n".format(self.familie) return "{0}{1}{2}".format(art_spezies, art_ordnung, art_familie) class Mensch(Saeuger): def __init__(self): self.spezies = "Mensch" Saeuger.__init__(self, "Primaten", "Menschenaffen") def get_art(self): return self.get_spezies() instanz = Mensch() print(instanz.get_art())
Alle vorausgehenden Beispiele bewirken eine sich gleichende Ausgabe, da es sich lediglich um unterschiedliche Varianten handelt, die letztendlich alle zum gleichen Ergebnis führen.
Ausgabe:
Der Mensch gehört im Tierreich zur Ordnung der Primaten und zur Familie der Menschenaffen.
Etwas anders sieht die Ausgabe vom folgenden Beispiel aus.
Dabei sollte beachtet werden, Variablen, denen ein Sternchen vorangestellt wurde, dienen der Speicherung von Werten
für Argumente in Tupeln. Mit zwei Sternchen versehende Variablen speichern hingegen Parameter und die Werte für
Argumente in Dictionaries. Diese Variante kann benutzt werden, wenn beim Erstellen von Klassen nicht von einer
stetig gleichbleibenden Anzahl von zu übergebenen Parametern bzw. von Parameter-Wertepaaren ausgegangen werden
kann.
Beispiel 7:
class Saeuger: def __init__(self, *args, **kwargs): self.ordnung = "Primaten" self.familie = "Menschenaffen" def get_argumente(self, *args): return "Antwort von der Klasse Saeuger: {}".format(args) class Mensch(Saeuger): def __init__(self, *args, **kwargs): Saeuger.__init__(self, *args, **kwargs) self.spezies = "Mensch" def get_keyword_argumente (self, **kwargs): return "Antwort von der Klasse Mensch: {}".format(kwargs) instanz = Mensch() print(instanz.get_argumente("Doe", "John")) print(instanz.get_keyword_argumente(Nachname = "Doe", Vornahme = "Jane"))
Ausgabe:
Antwort von der Klasse Saeuger: ('Doe', 'John')
Antwort von der Klasse Mensch: {'Nachname': 'Doe', 'Vornahme': 'Jane'}
Die Sichtbarkeit von Attributen wird zuweilen mit der Sichtbarkeit in anderen Script-
und Programmiersprachen verglichen, wobei dann die Schlüsselwörter public, protected und private aus diesen Sprachen
benutzt werden, doch hinken diese Vergleiche. Ein Grund für dieses Hinken, protected gibt es in Python praktisch
nicht.
Attribute und Methoden können mit Hilfe eines vorangestellten Präfixes, bestehend aus zwei __Unterstrichen, vor
einem Zugriff von außerhalb oder von einer erbenden Klasse aus geschützt werden, ein einzelner vorangestellter
Unterstrich hat hingegen für Python keine Bedeutung. Wird ein einzelner Unterstrich dennoch verwendet, dann nur
um anderen Programmierern, die ein Script weiterentwickeln möchten, mitzuteilen, dass dieses Attribut nicht unbedingt
geändert werden sollte.
Beispiel 8 (öffentliche Attribute):
class Saeuger: def __init__(self): self.variable01 = "öffentlich 01" self._variable02 = "öffentlich 02" self.__variable03 = "privat" class Mensch(Saeuger): def get_sichtbarkeitstest(self): test = "# Ausgabe get_sichtbarkeitstest(): {0:s}, {1:s}".format( self.variable01, self._variable02) return test instanz = Mensch() print(instanz.get_sichtbarkeitstest()) instanz = Saeuger() print("# Ausgabe Saeuger(): {}".format(instanz.variable01)) print("# Ausgabe Saeuger(): {}".format(instanz._variable02)) # Ausgabe get_sichtbarkeitstest(): öffentlich 01, öffentlich 02 # Ausgabe Saeuger(): öffentlich 01 # Ausgabe Saeuger(): öffentlich 02
Die Ausgaben von beiden Code-Listings wurden jeweils als Kommentare mit eingefügt, wobei es sich im nächsten Beispiel nicht um eine Print-Ausgabe handelt, sondern um die erhaltene Fehlermeldung beim Versuch auf ein mit zwei vorangestellten Unterstrichen versehendes Attribut zuzugreifen.
Beispiel 9 (mit geschütztem Attribut):
class Saeuger: def __init__(self): self.__geheimnis = "private" class Mensch(Saeuger): def get_sichtbarkeitstest(self): test = "# Ausgabe: {0:s}".format( self.__geheimnis) return test instanz = Mensch() print(instanz.get_sichtbarkeitstest()) # AttributeError: 'Mensch' object has no attribute '_Mensch__geheimnis'
Beispiel 10 (mit öffentlichem Attribut aber geschützter Methode):
class Saeuger: def __init__(self): self.oeffentlich = "öffentlich 01" class Mensch(Saeuger): def __get_sichtbarkeitstest(self): test = "# Ausgabe: {0:s}".format( self.oeffentlich) return test instanz = Mensch() print(instanz.__get_sichtbarkeitstest()) # AttributeError: 'Mensch' object has no attribute '__get_sichtbarkeitstest'
Einstieg in Python
OOP mit Python
Codes & Tutorials
Kleines Projekt