1. Was ist Vererbung? (Das DRY-Prinzip)
In vielen Software-Projekten gibt es Klassen, die sich sehr ähnlich sind. Stelle dir eine Fahrzeugflotte vor: Ein Auto, ein ElektroAuto und ein Lkw haben alle eine Marke, ein Modell, ein Baujahr, einen Grundpreis und können fahren.
Ohne Vererbung müsstest du all diese Variablen und Methoden in jeder einzelnen Klasse kopieren. Das verletzt eine der wichtigsten Regeln der Programmierung: DRY (Don't Repeat Yourself)!
In Python ist
Fahrzeug die Elternklasse (Basisklasse) und Auto die Kindklasse (abgeleitete Klasse).
Das Auto erbt automatisch alles, was ein Fahrzeug kann, und fügt eigene Besonderheiten wie sitzplaetze und hupen() hinzu!
- Vererbung (Kapitel 10): Ein Auto ist ein Fahrzeug. Ein Elektroauto ist ein Auto.
- Komposition (Kapitel 05): Ein Auto hat einen Motor. Eine Playlist hat viele Songs.
2. 📊 UML-Klassendiagramm: Die Vererbungshierarchie
Im UML-Diagramm wird Vererbung durch einen Pfeil mit geschlossener Dreiecksspitze (▲) dargestellt. Der Pfeil zeigt immer von der Kindklasse nach oben zur Elternklasse:
- modell: str
- baujahr: int
- grundpreis: float
- kilometerstand: float = 0.0
+ fahren(km: float) -> None
+ berechne_restwert(jahr: int) -> float
+ info() -> str
- anzahl_tueren: int = 5
+ hupen() -> str
+ info() -> str (überschrieben)
- aktuelle_ladung_kg: float = 0.0
+ beladen(kg: float) -> bool
+ entladen(kg: float) -> float
+ info() -> str (überschrieben)
- batterie_ladestand_kwh: float
- verbrauch_pro_100km: float = 18.0
+ reichweite() -> float
+ fahren(km: float) -> bool (mit Stromverbrauch)
+ aufladen(kwh: float) -> float
+ info() -> str (überschrieben)
3. Syntax: Wie funktioniert super() in Python?
Schritt 1: Vererbung deklarieren
Um von einer Klasse zu erben, schreibst du den Namen der Elternklasse in Klammern hinter den Klassennamen:
class Auto(Fahrzeug): # Auto erbt alle Attribute und Methoden von Fahrzeug! pass
Schritt 2: Der Aufruf von super().__init__(...)
Wenn die Kindklasse einen eigenen Konstruktor __init__ besitzt, überschreibt sie zunächst den Eltern-Konstruktor.
Damit die Eltern-Attribute (marke, modell, etc.) trotzdem sauber initialisiert werden, rufen wir mit super().__init__() den Konstruktor der Elternklasse auf:
class Auto(Fahrzeug): def __init__(self, marke: str, modell: str, baujahr: int, grundpreis: float, sitzplaetze: int = 5): # 1. Eltern-Konstruktor aufrufen (setzt marke, modell, baujahr, grundpreis, kilometerstand): super().__init__(marke, modell, baujahr, grundpreis) # 2. Zusätzliche, eigene Attribute der Kindklasse setzen: self.sitzplaetze: int = sitzplaetze
super().__init__() vergessensuper().__init__() vergisst, existieren Attribute wie self.marke oder self.kilometerstand am Kind-Objekt überhaupt nicht! Der Code stürzt beim ersten Zugriff mit einem AttributeError ab.
4. Typ-Prüfung: isinstance() und issubclass()
Weil ein ElektroAuto von Auto und dieses von Fahrzeug erbt, ist ein Elektroauto gleichzeitig eine Instanz aller drei Klassen:
tesla = ElektroAuto("Tesla", "Model 3", 2023, 42000.0, batterie_kapazitaet_kwh=60.0) print(isinstance(tesla, ElektroAuto)) # True print(isinstance(tesla, Auto)) # True print(isinstance(tesla, Fahrzeug)) # True print(isinstance(tesla, Lkw)) # False (Lkw ist ein Geschwisterzweig!) print(issubclass(ElektroAuto, Fahrzeug)) # True
5. 🎯 Deine Aufgaben in aufgabe.py
Öffne die Datei 10_vererbung_und_super/aufgabe.py und vervollständige die 4 Klassen:
💡 Lösungshinweise (Aufklappen bei Bedarf)
🔍 Tipp zu TODO 3 (Restwert berechnen)
alter = max(0, aktuelles_jahr - self.baujahr) wertverlust = self.grundpreis * 0.05 * alter restwert = self.grundpreis - wertverlust return max(self.grundpreis * 0.10, restwert)
🔍 Tipp zu TODO 10 (ElektroAuto fahren)
if km <= 0: return False benoetigt = (km / 100.0) * self.verbrauch_pro_100km if self.batterie_ladestand_kwh >= benoetigt: self.batterie_ladestand_kwh -= benoetigt super().fahren(km) # Erhöht den Kilometerstand in der Basisklasse! return True return False
6. 🧪 Lösung überprüfen
Führe im Terminal im Ordner 10_vererbung_und_super folgenden Befehl aus:
python3 test_aufgabe.py