Vererbung und Polymorphie in Python
Vererbung und Polymorphie sind zwei zentrale Konzepte der OOP. Lerne, wie du Klassen erweiterst und Methoden flexibel überschreibst.
Nachdem du gelernt hast, wie man Klassen und Objekte erstellt, geht es jetzt um zwei der mächtigsten Werkzeuge der objektorientierten Programmierung: Vererbung und Polymorphie. Mit Vererbung baust du neue Klassen auf bestehenden auf und vermeidest doppelten Code. Mit Polymorphie kannst du unterschiedliche Objekte einheitlich behandeln, obwohl sie sich verschieden verhalten. In diesem Beitrag schauen wir uns beide Konzepte mit anschaulichen Beispielen an.
Was bedeutet Vererbung?
Vererbung erlaubt es einer Klasse, die Eigenschaften und Methoden einer anderen Klasse zu übernehmen. Die übergebende Klasse heißt Basisklasse (oder Elternklasse), die erbende Klasse abgeleitete Klasse (oder Kindklasse). So musst du gemeinsame Funktionalität nur einmal schreiben.
class Tier:
def __init__(self, name):
self.name = name
def fressen(self):
return f"{self.name} frisst."
# Hund erbt von Tier
class Hund(Tier):
def bellen(self):
return f"{self.name} bellt: Wuff!"
bello = Hund("Bello")
print(bello.fressen()) # Bello frisst. (geerbt)
print(bello.bellen()) # Bello bellt: Wuff!Die Klasse Hund erbt automatisch den Konstruktor und die Methode fressen() von Tier, ergänzt aber eine eigene Methode bellen(). Du schreibst die gemeinsame Logik also nur einmal.
Methoden überschreiben
Eine abgeleitete Klasse kann geerbte Methoden anpassen, indem sie sie neu definiert. Das nennt man Überschreiben (englisch: overriding). Die Kindklasse ersetzt damit das Verhalten der Elternklasse für ihre Objekte.
class Tier:
def laut_geben(self):
return "Irgendein Geräusch"
class Katze(Tier):
def laut_geben(self): # überschreibt die Methode
return "Miau"
class Kuh(Tier):
def laut_geben(self):
return "Muh"
print(Katze().laut_geben()) # Miau
print(Kuh().laut_geben()) # MuhObwohl beide Klassen von Tier erben, liefert jede ihre eigene Version von laut_geben(). Das Original der Basisklasse wird für diese Objekte ignoriert.
Die Elternklasse mit super() aufrufen
Manchmal willst du die Methode der Elternklasse nicht komplett ersetzen, sondern erweitern. Dafür gibt es super(). Damit rufst du die ursprüngliche Methode auf und ergänzt sie. Besonders häufig nutzt man das im Konstruktor.
class Fahrzeug:
def __init__(self, marke):
self.marke = marke
class Auto(Fahrzeug):
def __init__(self, marke, ps):
super().__init__(marke) # Konstruktor der Basisklasse
self.ps = ps # eigenes Attribut ergänzen
auto = Auto("VW", 110)
print(auto.marke) # VW
print(auto.ps) # 110Mit super().__init__(marke) lässt du die Elternklasse das Attribut marke setzen, und kümmerst dich dann selbst um ps. So vermeidest du, Code aus der Basisklasse zu kopieren.
Polymorphie: gleiche Schnittstelle, verschiedenes Verhalten
Polymorphie bedeutet wörtlich "Vielgestaltigkeit". In der Praxis heißt das: Du kannst Objekte verschiedener Klassen gleich behandeln, solange sie dieselbe Methode anbieten. Python ruft automatisch die richtige Version auf.
class Hund:
def laut_geben(self):
return "Wuff"
class Katze:
def laut_geben(self):
return "Miau"
class Ente:
def laut_geben(self):
return "Quak"
# Eine Schleife über verschiedene Objekttypen
tiere = [Hund(), Katze(), Ente()]
for tier in tiere:
print(tier.laut_geben())
# Ausgabe:
# Wuff
# Miau
# QuakDie Schleife muss nicht wissen, um welches Tier es sich handelt. Sie ruft einfach laut_geben() auf, und jedes Objekt antwortet auf seine Weise. Das macht deinen Code flexibel und leicht erweiterbar.
Prüfen mit isinstance()
Mit der Funktion isinstance() kannst du prüfen, ob ein Objekt zu einer bestimmten Klasse gehört. Das funktioniert auch über Vererbungsketten hinweg: Ein Hund gilt auch als Tier, wenn er davon erbt.
class Tier:
pass
class Hund(Tier):
pass
bello = Hund()
print(isinstance(bello, Hund)) # True
print(isinstance(bello, Tier)) # True (durch Vererbung)
print(isinstance(bello, str)) # FalseDas ist nützlich, wenn du je nach Objekttyp unterschiedlich reagieren willst. Beachte aber, dass guter polymorpher Code oft ganz ohne solche Typprüfungen auskommt.
Fazit
Vererbung und Polymorphie machen objektorientierten Code wiederverwendbar und flexibel. Du hast gelernt, wie eine Klasse mit class Kind(Eltern) von einer anderen erbt, wie du Methoden überschreibst, mit super() die Basisklasse einbindest und wie Polymorphie es erlaubt, verschiedene Objekte einheitlich zu behandeln. Mit isinstance() kannst du Typen prüfen, solltest dich aber eher auf gemeinsame Methoden verlassen. Mein Tipp: Modelliere kleine Hierarchien wie Fahrzeuge oder Mitarbeiter, und du wirst schnell ein Gefühl dafür entwickeln, wann sich Vererbung lohnt und wo sie deinen Code wirklich verschlankt.