Method Resolution Order (MRO) is a mechanism in Python that defines the order in which classes are searched when looking for methods and attributes in the case of multiple inheritance.
C3 linearization is the algorithm used to construct the method resolution order. Understanding MRO is crucial when designing complex class hierarchies to avoid ambiguities and unexpected behavior of methods.
To find the MRO for any class, you can use the __mro__ attribute or the mro() function:
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', because B comes before C in MRO
The MRO cannot be changed explicitly, but you can control the order of base classes listing.
In what order will methods be called if a class inherits from multiple parents? For example:
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()
Many expect that "foo" will be called from Left, then from Right, then from Base — and that's correct. However, if the order of base classes is changed (class Child(Right, Left)), the order will change!
Correct answer:
The order of calls will be as defined in MRO. In the first case — Left, Right, Base. The MRO is constructed according to a specific algorithm (C3 linearization):
[Child, Left, Right, Base, object]
Story
Multiple inheritance logic, method overriding
The development team used multiple inheritance for mixins. It turned out that due to the incorrect order of base classes, the common logic of the mixin was "overridden" by the child class, and part of the business logic was not executed, leading to data loss.
Story
Wrong parent method called
In the finalizer method (__del__), it was expected that the base class method would be called. However, due to a misunderstanding of MRO, another inherited mixin method was called, where resource cleanup did not occur. As a result — memory leak.
Story
Using super() without understanding the call chain
In a Python 3 project, the client rewrote part of the code with multiple inheritance but forgot to update calls through super(). This led to situations of infinite recursion, where the method continuously called itself due to the erroneous method resolution order.