CodeOath
← All posts
Python70 min total · 18 parts

Python Fundamentals for Interviews: Data Structures, Comprehensions, and Gotchas

Contents — Part 15 of 18: Inheritance, super(), and MRO
Part 15 of 18 · ~1 min

Inheritance, super(), and MRO

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return f"{self.name} makes a sound"

class Dog(Animal):
    def speak(self):
        base = super().speak()          # calls Animal's speak() explicitly
        return f"{base}, specifically a bark"

Dog("Rex").speak()  # "Rex makes a sound, specifically a bark"

super() gives access to the parent class's version of a method being overridden, without hardcoding the parent class's name — which matters once multiple inheritance is involved, since hardcoding Animal.speak(self) bypasses Python's cooperative-inheritance resolution entirely.

Multiple inheritance and the MRO

class A:
    def greet(self):
        return "A"

class B(A):
    def greet(self):
        return "B -> " + super().greet()

class C(A):
    def greet(self):
        return "C -> " + super().greet()

class D(B, C):
    def greet(self):
        return "D -> " + super().greet()

D().greet()          # "D -> B -> C -> A"
D.__mro__             # (D, B, C, A, object) — the Method Resolution Order

Python uses the C3 linearization algorithm to compute a single, consistent Method Resolution Order (__mro__) for classes with multiple inheritance — super() doesn't mean "my direct parent," it means "the next class in the MRO," which is why B.greet's super().greet() reaches C before A in the diamond above, rather than jumping straight to A. This is a common point of confusion for anyone coming from a single-inheritance language.