ProgrammingBackend Developer

How does the Method Resolution Order (MRO) mechanism work in Python when it comes to class inheritance? Why is it important to understand the method resolution order, and how can it be determined/changed?

Pass interviews with Hintsage AI assistant

Answer

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.

Trick Question

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]

Examples of Real Errors Due to Ignorance of the Topic


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.