MRO stands for Method Resolution Order. It defines the order in which Python looks for methods and attributes in a hierarchy of classes when you use super()
.
Consider a “diamond inheritance” like this:
A
/ \
B C
\ /
D
A
.A
multiple times — causing bugs.__init__
) is called once, and in a predictable order.Python uses the C3 Linearization Algorithm to compute MRO.
class A:
def __init__(self):
print("A initialized")
class B(A):
def __init__(self):
super().__init__()
print("B initialized")
class C(A):
def __init__(self):
super().__init__()
print("C initialized")
class D(B, C):
def __init__(self):
super().__init__() # Initializes B -> C -> A
print("D initialized")
d = D() # Output order might surprise beginners
class A:
def __init__(self):
print("A initialized")
A
. It prints a message when initialized.class B(A):
def __init__(self):
super().__init__()
print("B initialized")
B
inherits from A
.super().__init__()
, which refers to A.__init__
.class C(A):
def __init__(self):
super().__init__()
print("C initialized")
C
inherits from A
.class D(B, C):
def __init__(self):
super().__init__() # MRO applies here
print("D initialized")
D
inherits from both B
and C
. This is where MRO kicks in.d = D()
?When we create an instance of D
, the following happens:
D
.D
inherits from B
and C
, and both inherit from A
. So Python uses C3 linearization to resolve this.To see the MRO:
print(D.mro())
Output:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
This means:
D
B
C
A
object
(the root class of all Python classes)super()
Uses MROWhen you call super().__init__()
inside D
, Python uses the MRO list:
D
→ that’s B
B
’s super()
calls the next one → C
C
’s super()
calls the next → A
A
doesn’t use super()
, so it ends thereNo class is repeated, and the initialization flows down this path.
A initialized
C initialized
B initialized
D initialized
Explanation:
D.__init__
→ B.__init__
→ C.__init__
→ A.__init__
super()
follows the MRO chain.ClassName.mro()
or help(ClassName)