Single inheritance and super()

RoadmapsPython

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. class BaseWorker: def __init__(self, name): self.name = name class CeleryWorker(BaseWorker): def __init__(self, name, queue): super().__init__(name) self.queue = queue ⚠️ **Trap: Signature Mismatch** If your subclass `__init__` takes different arguments than the parent, you must explicitly pass only what the parent expects to `super().__init__()`. Passing all arguments blindly raises a `TypeError`. class User: def __init__(self, username): pass class Admin(User): def __init__(self, username, role): super().__init__(username, role) # TypeError: __init__() takes 2 positional arguments but 3 were given ⚠️ **Trap: Multiple Inheritance & MRO** Using `super()` in complex hierarchies does not just call the direct parent, it follows the Method Resolution Order (MRO). This can cause unexpected arguments to be passed to siblings. This is covered fully in `mro`.

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 `BaseModel`s, 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 Admin(User):`, `User` 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'`.

What does this code do?

It raises a `TypeError`.

The subclass `UserModel` passes both `table` and `db_url` to `super().__init__()`, but the parent class `Model` only expects the `table` argument.

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: Class Creation and Instantiation

Previous: Instance, Class, and Static Methods

Next: Multiple Inheritance & The Diamond Problem

Next: MRO: Method Resolution Order (C3 linearization)

Next: Method Overriding

Return to Python Roadmap