Die Method Resolution Order (MRO) ist ein Mechanismus in Python, der bestimmt, in welcher Reihenfolge Klassen bei der Suche nach Methoden und Attributen in Fällen von Mehrfachvererbung durchsucht werden.
C3-Linearisierung (C3 linearization) ist ein Algorithmus, der zur Erstellung der Methodenauflösungsreihenfolge verwendet wird. Das Verständnis der MRO ist entscheidend für das Design komplexer Klassenhierarchien, um Mehrdeutigkeiten und unerwartetes Verhalten von Methoden zu vermeiden.
Die MRO für jede Klasse kann mithilfe des Attributs __mro__ oder der Funktion mro() ermittelt werden:
class A: def hello(self): print('A') class B(A): def hello(self): print('B') class C(A): def hello(self): print('C') class D(B, C): pass print(D.__mro__) # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) obj = D() obj.hello() # 'B', weil B vor C in der MRO steht
Die MRO kann nicht direkt geändert werden, aber man kann die Reihenfolge der Elternklassen steuern.
In welcher Reihenfolge werden die Methoden aufgerufen, wenn die Klasse von mehreren Eltern erbt? Zum Beispiel:
class Base: def foo(self): print('Base') class Left(Base): def foo(self): print('Left') super().foo() class Right(Base): def foo(self): print('Right') super().foo() class Child(Left, Right): pass Child().foo()
Viele erwarten, dass "foo" zuerst aus Left, dann aus Right, dann aus Base aufgerufen wird — so ist es auch. Allerdings ändert sich die Reihenfolge, wenn die Elternklassen umgestellt werden (class Child(Right, Left)).
Richtige Antwort:
Die Aufrufreihenfolge wird durch die MRO bestimmt. Im ersten Fall — Left, Right, Base. Die MRO wird nach einem bestimmten Algorithmus (C3-Linearisierung) erstellt:
[Child, Left, Right, Base, object]
Geschichte
Mehrfachvererbung von Logik, Methodenüberschreibung
Das Entwicklerteam verwendete Mehrfachvererbung für Mixins. Es stellte sich heraus, dass die allgemeine Logik des Mixins aufgrund einer falschen Reihenfolge der Elternklassen im abgeleiteten Klassenteil „überschrieben“ wurde, sodass ein Teil der Geschäftslogik nicht ausgeführt wurde, was zu Datenverlust führte.
Geschichte
Falsche Methode des Elternteils wird aufgerufen
Im finalisierenden Methodenaufruf (__del__) wurde erwartet, dass die Methode der Basisklasse aufgerufen wird. Aufgrund eines Missverständnisses der MRO wurde jedoch eine andere, vererbte Methode des Mixins aufgerufen, die keine Ressourcenbereinigung vornahm. Infolgedessen trat ein Speicherleck auf.
Geschichte
Verwendung von super() ohne Verständnis der Aufrufkette
In einem Python 3-Projekt hatte der Kunde einen Teil des Codes mit Mehrfachvererbung umgeschrieben und vergessen, die Aufrufe über super() zu aktualisieren. Dies führte zu Situationen mit unendlicher Rekursion, bei denen die Methode sich die ganze Zeit selbst aufgrund der fehlerhaften Reihenfolge der Methodenauflösung aufrief.