Understanding Python Method Resolution Order (MRO)
This article explains Python's Method Resolution Order (MRO), detailing its basic principles, the C3 linearization algorithm, and how attribute and method lookup work in single, multiple, and complex inheritance scenarios, accompanied by illustrative code examples.
In Python, the lookup order for class and instance attributes follows the Method Resolution Order (MRO), an algorithm that determines how methods and attributes are searched through the inheritance hierarchy.
Basic principle of MRO – MRO decides the sequence in which Python searches base classes for a method or attribute. This is especially important for classes with multiple inheritance because it defines the exact order of lookup.
Lookup sequence – When Python searches for a method or attribute, it follows these steps:
Current instance: search the instance namespace first.
Current class: if not found in the instance, search the class namespace.
Parent classes: if still not found, search each parent class according to the MRO order.
MRO algorithm – Python 3.x uses the C3 linearization algorithm, which guarantees a consistent and sensible order even in complex multiple‑inheritance structures. The rules are:
If a class has no base classes, its MRO is just itself.
If a class has base classes, its MRO is the class followed by the merged MROs of its bases.
Higher‑priority bases appear earlier in the merged list.
When multiple bases are present, they are ordered as they appear in the class definition.
Common ancestors appear only once.
Example code
Example 1: Single inheritance
class Base:
pass
class Derived(Base):
pass
print(Derived.mro()) # Output: [Derived, Base, object]Example 2: Multiple inheritance
class A:
pass
class B:
pass
class C(A, B):
pass
print(C.mro()) # Output: [C, A, B, object]Example 3: Complex inheritance
class A:
pass
class B:
pass
class C(A, B):
pass
class D(B):
pass
class E(C, D):
pass
print(E.mro()) # Output: [E, C, A, D, B, object]Example 4: Attribute lookup
class A:
x = 10
class B:
x = 20
class C(A, B):
pass
class D(B):
x = 30
class E(C, D):
pass
e = E()
print(e.x) # Output: 10
print(E.mro()) # Output: [E, C, A, D, B, object]Example 5: Method lookup
class A:
def greet(self):
print("Hello from A")
class B:
def greet(self):
print("Hello from B")
class C(A, B):
pass
class D(B):
pass
class E(C, D):
pass
e = E()
e.greet() # Output: Hello from A
print(E.mro()) # Output: [E, C, A, D, B, object]Advanced examples
Example 1: Attribute lookup with deeper hierarchy
class Alpha:
value = 'Alpha'
class Bravo:
value = 'Bravo'
class Charlie(Alpha, Bravo):
pass
class Delta(Bravo):
value = 'Delta'
class Echo(Charlie, Delta):
pass
echo_instance = Echo()
print(echo_instance.value) # Output: AlphaExample 2: Method overriding
class Lion:
def speak(self):
return "Roar"
class Dog:
def speak(self):
return "Woof"
class Tiger(Lion):
pass
class Mutt(Dog):
def speak(self):
return "Bark"
class Beast(Tiger, Mutt):
pass
beast_instance = Beast()
print(beast_instance.speak()) # Output: RoarSummary
Through these examples we see how Python's MRO works: it provides a predictable order for method and attribute lookup in multiple‑inheritance scenarios, helping developers write reliable and maintainable code by understanding the path the interpreter follows.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.