Inheritance & super() (MRO)

RoadmapsPython Backend

Overview

Inheritance allows a new class to inherit attributes and methods from an existing class, establishing an 'is-a' relationship. The `super()` function returns a proxy object that delegates method calls to a parent or sibling class. Think of inheritance like a master template and `super()` as a phone line explicitly calling the master template to avoid repeating setup logic. When overriding `__init__`, calling `super().__init__()` ensures the parent's initialization runs.

It reduces code duplication by centralizing shared logic in base classes, making it easier to maintain and extend functionality.

Where used: Django models (`models.Model`), Pydantic BaseModels, FastAPI API routers

Why learn this

Code walkthrough

class Worker:
    def start(self):
        print('worker started')

class CeleryWorker(Worker):
    def start(self):
        super().start()
        print('connected to broker')

w = CeleryWorker()
w.start()

Focus: super().start()

Aha moment

class APIError(Exception):
    def __init__(self, code):
        self.code = code

class NotFoundError(APIError):
    def __init__(self, code):
        pass

err = NotFoundError(404)
print(hasattr(err, 'code'))

Prediction: What does this print: True or False?

Common guess: True

Because `NotFoundError` overrides `__init__` and does NOT call `super().__init__(code)`, the `APIError`'s `__init__` is skipped, so `self.code` is never set.

Common mistakes

Glossary

proxy object
A special object that stands in for another object, forwarding or delegating commands to it. Example: `super()` returns a proxy object so that `super().__init__()` calls the parent class's `__init__` without naming the parent directly.
base classes
The original or parent classes that other classes are built upon and inherit features from. Example: in `class Dog(Animal):`, `Animal` is the base class.

Recall questions

Understanding checks

What happens when a child class overrides `__init__` but forgets to call `super().__init__()`?

The parent's initialization logic will be skipped.

This is dangerous because any attributes that the parent normally sets up in its `__init__` won't be created, leading to an `AttributeError` when other inherited methods try to access them.

What does this code print?

It prints `A` followed by `B`.

The call to `b.ping()` runs the `ping` method in `B`. Inside `B.ping`, `super().ping()` delegates to the parent class `A`, printing 'A'. Then it resumes in `B` and prints 'B'.

Practice tasks

Extend an API Request class

Modify the `SecureRequest` class so it takes a `url` and a `token`. Call `super().__init__(url)` to handle the URL, then store the `token` as an instance variable.

Challenge

Implement a Database Model hierarchy

Create a base class `Model` with a `save` method printing 'saving to db'. Create a `UserModel` inheriting from `Model` whose `save` prints 'validating user' then calls the parent's `save` using `super()`.

Continue learning

Previous: instance / class / static methods

Return to Python Backend Roadmap