2026, Jan 05 17:00

When to use super() in Python inheritance: skip redundant overrides, extend behavior when needed

Learn when to use super() in Python inheritance: avoid redundant overrides, extend base methods with clear, maintainable class hierarchies and consistent APIs.

Understanding when to use super() in Python inheritance often comes down to a simple rule of thumb: inherit by default, override only when you’re adding or changing behavior. Let’s walk through a small example that caused confusion and see what actually matters for clean, predictable class hierarchies.

Problem setup

Consider a base type that initializes some state and exposes a couple of methods. A derived type overrides methods but only calls the parent implementation.

class Creature:
    def __init__(self):
        self.limb_count = 4
        self.is_domestic = True
        self.has_tail = True
        self.is_mammal = True
    def check_mammal(self):
        if self.is_mammal:
            print("It is a mammal.")
    def check_domestic(self):
        if self.is_domestic:
            print("It is a domestic animal.")
class Hound(Creature):
    def __init__(self):
        super().__init__()
    def check_mammal(self):
        super().check_mammal()

There’s also a tempting idea to introduce a new method that calls the existing one and adds extra output.

def mammal_can_dance(self):
    self.check_mammal()
    print("and can dance")

What’s actually going on

In Python, methods are inherited. If a subclass doesn’t override a method, it gets the parent’s implementation automatically. Overriding a method and only calling super() without adding anything new produces the same behavior as not overriding at all. In other words, an override that only delegates is redundant.

This applies to both regular methods and __init__. If your subclass __init__ doesn’t do anything beyond super().__init__(), it can be omitted entirely; the base initializer will be used anyway.

Practical fix

If a subclass exists only to inherit behavior and doesn’t modify it, keep it minimal.

class Hound(Creature):
    pass

If you do need the parent’s behavior and want to add something on top, call super() and extend the result. That’s when an override earns its keep.

class Alpha(Beta):
    def baz(self):
        stuff = super().baz()
        return stuff + ['quux']

This pattern preserves the base behavior and cleanly layers the subclass’s contribution.

Why not put the parent call in a new method?

You can. The catch is discoverability and API expectations. If you add a brand-new method that wraps the existing one, callers need to know to use that new method instead of the established one. Overriding the existing method keeps the public surface consistent while still allowing you to augment the behavior.

Consumers shouldn’t have to learn a parallel API when they expect a standard method name; override the standard entry point and extend it with super().

Why this matters

Minimal overrides reduce noise and make intent obvious. If a subclass doesn’t change behavior, the absence of overrides communicates that clearly. When behavior does change, using super() expresses that the subclass extends rather than replaces the parent logic. This makes hierarchies easier to maintain and reason about.

It also nudges you toward a consistent interface. As a small naming note, class names are typically singular in such hierarchies (e.g., Animal, Dog) to reflect the concept modeled by each type.

Takeaways

Inherit by default. Skip overrides that only call super() and add nothing. When you need to augment the base behavior, override and use super() to compose the result. Prefer extending the established method over creating a separate wrapper so that callers don’t have to learn a new entry point. Keep naming clean and singular to match common conventions.