Die Mehrfachvererbung – die Möglichkeit für eine Klasse, von mehreren Basisklassen zu erben – wurde in Python inspiriert von anderen OOP-Sprachen (z. B. C++), wo sie hilft, wiederverwendbare Mixins zu erstellen. Die Entwicklung des Mechanismus zur Methodenaufrufreihenfolge (MRO) nahm viel Zeit in Anspruch, um Vorhersehbarkeit bei Methoden-Kollisionen sicherzustellen.
Eine Klasse kann Methoden mit demselben Namen aus verschiedenen Basisklassen erhalten. Wie bestimmt man, welche Methode bei einem Aufruf verwendet werden soll? Ohne ein klares Schema führt dies zu schwer fassbaren Fehlern.
Python implementiert den MRO-Algorithmus (C3-Linearization), der eine strenge Reihenfolge für die Methoden-Suche bei der Auflösung von Konflikten in der Hierarchie definiert. Alles wird transparent, wenn die Funktion super() und die Methode __mro__ der Klassen zur Analyse der Vererbungskette verwendet werden.
Beispielcode:
class A: def foo(self): print("A") class B(A): def foo(self): print("B") super().foo() class C(A): def foo(self): print("C") super().foo() class D(B, C): def foo(self): print("D") super().foo() D().foo() print(D.__mro__)
Wesentliche Merkmale:
__mro__ eingesehen werden;Was passiert, wenn die Namen der Elternmethoden identisch sind?
Antwort: Der Methodenaufruf erfolgt in der durch MRO definierten Reihenfolge. Die erste gefundene Methode mit dem erforderlichen Namen in der Kette wird aufgerufen.
Kann man super() ohne explizite Übergabe von self verwenden?
Antwort: In Python 3 - ja, der Aufruf super().method() im Körper einer Klassenmethode ist äquivalent zu super(Klasse, self).method(), jedoch nur innerhalb der Klasse.
Kann man die MRO-Reihenfolge einer bestehenden Klasse ändern?
Antwort: Die MRO-Reihenfolge ist nach der Deklaration der Klasse statisch, kann jedoch untersucht oder eine neue Klasse mit einer anderen Vererbungsreihenfolge erstellt werden.
Im Projekt wurden zwei Mixins mit ähnlicher Methode erstellt, die abgeleitete Klasse verwendet beide Mixins, ruft jedoch die Methoden direkt über den Klassennamen auf, wodurch die Ereignisreihenfolge verletzt wird.
Vorteile:
Nachteile:
In jedem Methodenkontext wird super() verwendet, was den Aufruf in der Kette garantiert und das benötigte Verhalten nicht überspringt.
Vorteile:
Nachteile: