Mit Vererbung baust du neue Klassen auf bestehenden auf. Die neue Klasse (Unterklasse) übernimmt alle Attribute und Methoden der Oberklasse und kann sie erweitern oder ersetzen.
Grundprinzip
class Tier:
def __init__(self, name):
self.name = name
def laut(self):
return "..."
def vorstellen(self):
return f"{self.name} macht {self.laut()}"
class Hund(Tier):
def laut(self):
return "Wuff"
class Katze(Tier):
def laut(self):
return "Miau"
for t in [Hund("Rex"), Katze("Mimi"), Tier("Etwas")]:
print(t.vorstellen())Rex macht Wuff Mimi macht Miau Etwas macht ...
Hund und Katze erben __init__ und vorstellen, überschreiben aber laut. Obwohl vorstellen nur in Tier steht, ruft es automatisch die passende laut-Version auf. Das nennt man Polymorphie (Vielgestaltigkeit): derselbe Aufruf, je nach Objekt anderes Verhalten.
super(): die Oberklasse aufrufen
Wenn die Unterklasse eigene Daten braucht, ruft sie mit super() den Konstruktor der Oberklasse auf:
class Fahrzeug:
def __init__(self, marke):
self.marke = marke
def info(self):
return f"Fahrzeug: {self.marke}"
class Auto(Fahrzeug):
def __init__(self, marke, tueren):
super().__init__(marke)
self.tueren = tueren
def info(self):
return super().info() + f", {self.tueren} Türen"
a = Auto("VW", 4)
print(a.info())Fahrzeug: VW, 4 Türen
Typen prüfen
class A: pass
class B(A): pass
b = B()
print(isinstance(b, B), isinstance(b, A), isinstance(b, str))
print(issubclass(B, A))
print(B.__mro__)True True False True (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
isinstance prüft, ob ein Objekt zu einer Klasse (oder deren Unterklasse) gehört. __mro__ zeigt die Method Resolution Order: In dieser Reihenfolge sucht Python nach Methoden.
Mehrfachvererbung
Eine Klasse kann von mehreren erben. Python löst Konflikte nach der MRO:
class Fliegt:
def bewegen(self):
return "fliegt"
class Schwimmt:
def bewegen(self):
return "schwimmt"
class Ente(Fliegt, Schwimmt):
pass
print(Ente().bewegen())
print([k.__name__ for k in Ente.__mro__])fliegt ['Ente', 'Fliegt', 'Schwimmt', 'object']
Abstrakte Klassen
Wenn eine Oberklasse nur eine Vorlage sein soll, die Unterklassen ausfüllen müssen, nimmst du das Modul abc:
from abc import ABC, abstractmethod
class Form(ABC):
@abstractmethod
def flaeche(self): ...
class Quadrat(Form):
def __init__(self, a):
self.a = a
def flaeche(self):
return self.a ** 2
print(Quadrat(3).flaeche())
try:
Form()
except TypeError as e:
print("Nicht erlaubt:", "abstract" in str(e))9 Nicht erlaubt: True
Komposition statt Vererbung
Nicht alles ist eine "ist-ein"-Beziehung. Ein Auto ist kein Motor, es hat einen. In solchen Fällen speicherst du ein Objekt als Attribut (Komposition):
class Motor:
def starten(self):
return "brumm"
class Auto:
def __init__(self):
self.motor = Motor()
def starten(self):
return self.motor.starten()
print(Auto().starten())brumm
Merke
class Unter(Ober):erbt alles von der Oberklasse- Methoden lassen sich überschreiben;
super()ruft die Oberklasse auf - Polymorphie: gleicher Aufruf, je nach Objekt anderes Verhalten
isinstance,issubclass,__mro__für Typfragen- Abstrakte Klassen mit
ABCund@abstractmethod - "hat ein" bedeutet Komposition, "ist ein" bedeutet Vererbung
Aufgabe
Erstelle eine Oberklasse Form mit flaeche() und zwei Unterklassen Rechteck und Kreis. Gib in einer Schleife alle Flächen aus.