Keep your place in this quest

Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.

Wenn eine Klasse von einer Elternklasse erbt, kann die Kindklasse eigene Instanzvariablen und Methoden haben, aber manchmal muss sie dennoch Teile des Codes der Elternklasse verwenden.

Hier kommt die Funktion super() ins Spiel.
Sie ermöglicht es der Kindklasse, Methoden (und indirekt Attribute) ihrer Elternklasse aufzurufen — ohne den Namen der Elternklasse fest codieren zu müssen.

Eine der häufigsten Anwendungen von super() ist der Aufruf des Konstruktors der Elternklasse (__init__) aus der Kindklasse, sodass die Elternklasse ihre eigenen Attribute einrichten kann, bevor die Kindklasse neue hinzufügt.

Wenn du eine Kindklasse erstellst, die eine eigene init-Methode definiert, überschreibt sie die init der Elternklasse. Das bedeutet, dass beim Erzeugen eines Objekts der Kindklasse nur die init der Kindklasse ausgeführt wird — der Konstruktor der Elternklasse wird nicht automatisch aufgerufen. Dadurch werden jegliche Initialisierungslogik, Standardwerte oder Attribute, die im init der Elternklasse definiert sind, ganz übersprungen und sind im Kind-Objekt nicht definiert. Das kann unerwartete Fehler verursachen, wenn die Elternklasse wichtige Initialisierungen vornimmt. Um dieses Verhalten nicht zu verlieren, solltest du super().__init__() im Konstruktor der Kindklasse aufrufen, damit explizit die Initialisierung der Elternklasse vor der Ergänzung oder Überschreibung in der Kindklasse ausgeführt wird.

Lass uns das jetzt genauer anschauen!


Warum super().__init__() verwenden?

Wenn du eine Unterklasse erstellst, möchtest du ihr möglicherweise zusätzliche Daten mitgeben.
Gleichzeitig sollen aber die Attribute der Elternklasse richtig initialisiert werden. Anstatt den Initialisierungscode der Elternklasse neu zu schreiben, rufst du ihn einfach mit super().__init__() auf.

Beispiel: Neuen Attribut in einer Unterklasse hinzufügen

Angenommen, wir haben eine Animal-Klasse, die name und age speichert.
Wir möchten eine Dog-Unterklasse machen, die auch die breed (Rasse) des Hundes speichert, aber weiterhin den Konstruktor von Animal verwenden, um name und age zu setzen.

class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # Aufruf des Konstruktors von Animal
        self.breed = breed           # Hinzufügen eines eigenen Attributs von Dog

Schritt-für-Schritt-Erklärung

  1. Wenn wir ein Dog-Objekt erzeugen, läuft die __init__-Methode der Dog-Klasse.
  2. Innerhalb von Dog.__init__ ruft die Zeile super().__init__(name, age) die Animal.__init__ Methode auf.
  3. Der Konstruktor der Elternklasse (Animal.__init__) setzt self.name und self.age.
  4. Die Kontrolle kehrt zu Dog.__init__ zurück, das dann self.breed setzt.

So erreicht man:

  • Die Attribute der Elternklasse werden genau so initialisiert, wie es die Elternklasse vorgesehen hat.
  • Die Kindklasse kann ihre eigenen Attribute hinzufügen, ohne Code zu duplizieren.

Verwendung der Klasse

dog = Dog("Rex", 4, "Golden Retriever")

print(dog.name)   # Rex
print(dog.age)    # 4
print(dog.breed)  # Golden Retriever

Warum super() besser ist als direkter Aufruf des Elternklassennamens

Du könntest Animal.__init__(self, name, age) direkt aufrufen, aber die Verwendung von super() ist flexibler:

  • Es handhabt automatisch Mehrfachvererbung (wenn deine Klasse von mehreren Eltern erbt).
  • Es macht deinen Code wartungsfreundlicher — wenn du die Elternklasse umbenennst, musst du nicht jede Referenz anpassen.
  • Es signalisiert klar, dass du absichtlich eine Methode der Elternklasse aufrufst.
TIPP: Rufe immer `super().__init__()` auf, bevor du eigene Attribute der Kindklasse setzt, damit alle Attribute der Elternklasse einsatzbereit sind.

Zusammenfassung

super() ist deine Verbindung zur Elternklasse. Verwende es, wenn du:

  • Initialisierungscode der Elternklasse wiederverwenden möchtest.
  • Funktionalität der Elternklasse erweitern möchtest, ohne sie zu duplizieren.
  • Deinen Code klar, wartbar und bereit für Änderungen in der Klassenhierarchie halten willst.

In der nächsten Lektion schauen wir uns private Methoden und Variablen an — eine Möglichkeit, die internen Daten deiner Klasse vor Zugriff oder Änderungen von außen zu schützen.