MOD-19 · Sequence #19 · Object-Oriented Programming

Python Inheritance & Polymorphism

Inheritance allows classes to derive attributes and methods from base classes. Understanding super() for cooperative multiple inheritance, the Method Resolution Order (MRO), and method overriding is essential for scalable object-oriented software.

Live Interactive Code Snippet (Python 3.12 CPython WASM) Open in Practice Mode →
class Person:
    def __init__(self, name):
        self.name = name

class Student(Person):
    def __init__(self, name, grad_year):
        super().__init__(name)
        self.grad_year = grad_year

Core Principles & Mental Models

1. Single Inheritance and super()

Initializing Base Class State

  • A derived class inherits public methods from its base class: `class Child(Parent):`.
  • `super().__init__(...)` delegates initialization to the parent class, ensuring base class state is properly constructed before derived initialization.
  • Subclasses can override base methods to specialize behavior.
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def get_role(self):
        return "Standard Employee"

class Manager(Employee):
    def __init__(self, name, salary, team_size):
        super().__init__(name, salary)
        self.team_size = team_size

    def get_role(self):
        return f"Manager leading {self.team_size} engineers"

m = Manager("Sarah", 120000, 8)
print(m.name, "->", m.get_role())
💡 Key Takeaway: Always call super().__init__() in derived classes to ensure base class invariants are satisfied.

2. The C3 Linearization Algorithm (MRO)

Resolving Method Lookups in Multiple Inheritance

  • Python supports multiple inheritance: `class C(A, B):`.
  • CPython computes the Method Resolution Order using the C3 Linearization algorithm.
  • You can inspect any class's resolution order via `ClassName.__mro__`.
print("Manager MRO:", [c.__name__ for c in Manager.__mro__])
💡 Key Takeaway: MRO determines the exact order Python traverses classes when looking up attributes and super() calls.

Interactive Walkthrough Examples

Polymorphic Processing of Geometric Shapes (Basic)

Using polymorphic method calls across Circle and Rectangle subclasses.

import math

class Shape:
    def area(self) -> float:
        raise NotImplementedError("Subclasses must implement area()")

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return math.pi * self.radius ** 2

class Rectangle(Shape):
    def __init__(self, w, h):
        self.w = w
        self.h = h
    def area(self):
        return self.w * self.h

shapes: list[Shape] = [Circle(3), Rectangle(4, 5)]
for s in shapes:
    print(f"{type(s).__name__} area: {s.area():.2f}")

Explanation: Polymorphism allows treating different subclasses through a uniform interface.

Common Misconceptions & Exam Traps

Common Pitfall: Forgetting to Call `super().__init__()` in Derived Classes

If super().__init__() is omitted, base class attributes are never attached to the child instance.

Buggy Code
class Parent:
    def __init__(self):
        self.database_conn = "Active"

class Child(Parent):
    def __init__(self):
        # Forgot super().__init__()!
        self.ready = True

c = Child()
# print(c.database_conn) -> AttributeError: 'Child' object has no attribute 'database_conn'
Correct Solution
class Child(Parent):
    def __init__(self):
        super().__init__()
        self.ready = True

Exam Trap Note: Exams frequently ask why a child object raises an AttributeError for a field defined on its parent.

Conceptual Knowledge Self-Check Quiz

Q1: Which algorithm does CPython use to determine the Method Resolution Order (MRO)?

  1. Dijkstra's shortest path
  2. C3 Linearization
  3. Depth-First Search without backtracking
  4. Bellman-Ford

CPython employs the C3 Linearization algorithm to guarantee monotonicity and local precedence in inheritance hierarchies.

Algorithmic Practice Challenges

Idiomatic Best Practices

  • ✅ Favor composition over inheritance ("has-a" instead of "is-a") when classes only share behavior rather than conceptual identity.
  • ✅ Always use `super()` instead of hardcoding explicit parent class names.

All 26 Curriculum Modules