๐Ÿ” Python OOP

Method Overriding in Python

A complete beginner-friendly guide to Method Overriding โ€” covering how subclasses redefine inherited behaviour, the super() function, Method Resolution Order (MRO), overriding vs overloading, real-world examples, and why overriding is central to polymorphism.

๐Ÿ“…

Last Updated

March 2026

โฑ๏ธ

Read Time

22 min

๐ŸŽฏ

Level

Beginner to Intermediate

What is Method Overriding in Python?

Method Overriding is an Object-Oriented Programming technique in which a subclass provides its own specific implementation of a method that is already defined in its parent (superclass). When the overridden method is called on an instance of the subclass, Python runs the subclass's version instead of the parent's version โ€” even though both methods share the exact same name.

Think of it like a generic company policy being customised by a specific department. A company might have a general 'Employee.calculate_bonus()' policy, but the Sales department might override it with its own commission-based bonus calculation, and the Engineering department might override it with a performance-review-based calculation. Both departments are still 'Employees' following the same overall structure, but each customises the specific behaviour that matters to them.

Method overriding is one of the primary mechanisms that makes runtime polymorphism possible in Python. Because Python resolves method calls dynamically at runtime (a concept sometimes called 'late binding'), the exact method that executes depends on the actual type of the object at the moment the call is made โ€” not on the type of the reference or variable holding it. This is what allows a single line of code like animal.speak() to produce completely different output depending on whether animal is a Dog, a Cat, or a Bird.

Unlike some statically typed languages, Python does not require any special keyword (like Java's @Override annotation or C++'s virtual keyword) to enable overriding โ€” every method in Python is overridable by default. Simply defining a method with the same name in a subclass automatically overrides the parent's version. This simplicity is very Pythonic, but it also means developers must be more careful and deliberate, since there is no compiler warning if an override is accidental or a typo.

Method overriding is used constantly in real Python codebases โ€” Django model methods like save() are frequently overridden to add custom logic before saving to the database, and Python's own built-in dunder methods like __str__ and __eq__ are almost always overridden in user-defined classes to customise how objects are printed or compared.

Origins of Method Overriding โ€” A Brief History

Method overriding is deeply tied to the history of polymorphism and dynamic dispatch in programming languages. Understanding its roots clarifies why Python implements it the way it does today.

  • โ–ถ

    1967 โ€” Simula 67 โ€” Introduced 'virtual procedures,' the earliest form of overriding, allowing a subclass procedure to replace a superclass procedure of the same name when invoked polymorphically.

  • โ–ถ

    1972 โ€” Smalltalk โ€” Formalised 'message passing' where every method call is resolved dynamically at runtime based on the receiving object's actual class โ€” a model of dynamic dispatch that heavily influenced Python's own method resolution behaviour.

  • โ–ถ

    1983 โ€” C++ virtual Functions โ€” C++ required the explicit virtual keyword for a base class method to be eligible for overriding via dynamic dispatch; without it, C++ defaults to static, compile-time binding, unlike Python's fully dynamic model.

  • โ–ถ

    1995 โ€” Java @Override โ€” Java made overriding straightforward by default but later added the optional @Override annotation (Java 5, 2004) purely as a compile-time safety check to catch accidental signature mismatches.

  • โ–ถ

    1991 โ€” Python's Dynamic Dispatch Model โ€” Guido van Rossum designed Python so that all method resolution happens dynamically at runtime by default, with no special keyword required to enable overriding โ€” reflecting Python's broader philosophy of simplicity and flexibility over explicit ceremony.

  • โ–ถ

    1995 โ€” Python's super() Function โ€” Introduced early in Python's history and significantly improved in Python 2.2 (2001) alongside new-style classes, super() gave developers a clean, cooperative way to call a parent class's overridden method from within the subclass's override.

  • โ–ถ

    2001 โ€” C3 Linearization Algorithm Adopted (Python 2.3) โ€” Python adopted the C3 linearization algorithm to compute a well-defined Method Resolution Order (MRO) for multiple inheritance, ensuring overriding behaves predictably even in complex class hierarchies.

This history explains why Python's overriding model feels so effortless compared to Java or C++: Python was designed from the very beginning around dynamic dispatch as the default behaviour, rather than treating it as an opt-in feature requiring special keywords.

Why Method Overriding Matters โ€” Core Goals

Before exploring syntax, it helps to understand exactly what problems method overriding solves. These goals explain why it is one of the most frequently used OOP techniques in real Python projects.

๐ŸŽญ
Enables Runtime Polymorphism

The same method call behaves differently depending on the actual object's class, letting a single line of code work correctly across many different subclasses.

๐Ÿงฉ
Customises Inherited Behaviour

A subclass can adapt or specialise a parent's general-purpose method to match its own specific needs, without duplicating the entire class from scratch.

โ™ป๏ธ
Supports Code Reuse via super()

An overriding method can still call the parent's original implementation using super(), extending rather than completely replacing existing behaviour.

๐Ÿ”Œ
Powers Framework Hook Points

Frameworks like Django and Flask define base methods specifically expecting subclasses to override them, creating clean extension points for custom logic.

๐Ÿ“
Keeps Interfaces Consistent

Overriding lets every subclass honour a shared method name and signature, while implementing the internal logic however is appropriate for that subclass.

How Method Overriding Works โ€” The Basics

Overriding a method in Python requires nothing more than defining a method with the exact same name in a subclass that already exists in its parent class. There is no special syntax, decorator, or keyword required for basic overriding to take effect.

๐Ÿ”„ Automatic, Keyword-Free Overriding

As soon as Python sees a method definition in a subclass that shares a name with a method in the parent class, the subclass's version completely replaces the parent's version for instances of that subclass. This happens automatically โ€” Python does not require you to explicitly declare an intention to override, unlike some other languages.

๐Ÿงญ Dynamic Dispatch at Runtime

When you call obj.method(), Python looks up method starting from obj's actual class, not from whatever type a variable is annotated or assumed to hold. This lookup process โ€” walking up the class hierarchy in a specific, well-defined order โ€” is called the Method Resolution Order (MRO), and it is exactly what determines which version of an overridden method actually executes.

๐Ÿชœ Calling the Parent's Version with super()

Overriding does not have to mean fully discarding the parent's implementation. The built-in super() function lets an overriding method call the parent class's original version of the same method โ€” often to reuse shared setup logic before adding subclass-specific behaviour on top. This pattern, called method extension, is extremely common in professional Python code, especially in __init__ constructors.

How Python Resolves an Overridden Method Call โ€” Flowchart

When you call a method on an object, Python runs a precise lookup process to determine exactly which version of that method should execute โ€” especially important when multiple classes in the hierarchy define a method with the same name. The flowchart below traces this resolution step by step.

๐Ÿ“ Method Call Madeanimal.speak()
runtime lookup
๐Ÿ” Identify Actual Classtype(animal) โ†’ Dog
build search order
๐Ÿ“‹ Compute MRODog โ†’ Animal โ†’ object (C3 linearization)
check first class in MRO
โ“ Method Found on Dog?Does Dog define speak() itself?
โœ… found on Dog
โœ… Run Dog.speak()Subclass override executes
inside override
โฌ†๏ธ Walk Up to AnimalCheck next class in MRO
๐Ÿชœ super().speak() Called?Optional โ€” explicitly invokes parent version
either path completes
๐Ÿ–จ๏ธ Output Producede.g. "Woof!"

Code Execution Flow โ€” from source to output

Key insight: Python always starts the search from the object's actual class, not from the type of the variable or reference used to call the method. This is precisely what makes overriding work polymorphically โ€” the exact same line animal.speak() produces different behaviour purely based on what animal actually is at runtime.

Method Overriding in Action โ€” Animal Sound Example

The classic way to demonstrate method overriding is an Animal hierarchy, where every animal makes a sound, but each subclass overrides the exact sound it makes.

๐Ÿ Pythonanimal_sounds.py
class Animal:
    def __init__(self, name):
        self.name = name

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

class Dog(Animal):
    def speak(self):   # overrides Animal.speak()
        return f"{self.name} says Woof!"

class Cat(Animal):
    def speak(self):   # overrides Animal.speak()
        return f"{self.name} says Meow!"

class Puppy(Dog):
    def speak(self):
        # extends the parent's overridden version using super()
        original = super().speak()
        return f"{original} (but in a tiny puppy voice)"

animals = [Animal("Generic"), Dog("Rex"), Cat("Whiskers"), Puppy("Buddy")]
for a in animals:
    print(a.speak())

Output

Generic makes a generic sound. Rex says Woof! Whiskers says Meow! Buddy says Woof! (but in a tiny puppy voice)

Practice This Code โ€” Live Editor

Line-by-Line Explanation

  • โ–ถ

    class Dog(Animal) with its own def speak(self) โ€” Simply defining a method with the same name automatically overrides the parent's version; no special keyword is needed in Python.

  • โ–ถ

    class Puppy(Dog) โ€” Demonstrates that overriding works across multiple inheritance levels; Puppy overrides Dog's already-overridden version of speak().

  • โ–ถ

    super().speak() โ€” Calls Dog's version of speak() from within Puppy's override, reusing the existing logic instead of duplicating the 'Woof!' string โ€” this is method extension, not full replacement.

  • โ–ถ

    for a in animals: print(a.speak()) โ€” This single loop calls speak() polymorphically; Python automatically runs the correct overridden version based on each object's actual class.

  • โ–ถ

    The output shows four different behaviours from one method name (speak) โ€” a direct demonstration of runtime polymorphism enabled by overriding.

The super() Function โ€” Cooperative Overriding

The super() function is the standard, Pythonic way to call a parent class's original method from within an overriding method. It is used constantly in real-world code, especially inside __init__ constructors, to ensure the parent class's setup logic still runs.

๐Ÿ Pythonsuper_constructor_demo.py
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def details(self):
        return f"{self.name} earns {self.salary}"

class Manager(Employee):
    def __init__(self, name, salary, team_size):
        super().__init__(name, salary)   # reuse Employee's setup logic
        self.team_size = team_size

    def details(self):
        base = super().details()          # reuse Employee's overridden method
        return f"{base}, manages a team of {self.team_size}"

m = Manager("Priya", 95000, 8)
print(m.details())

Output

Priya earns 95000, manages a team of 8

Without super(), the Manager.__init__ would have to duplicate the exact logic of setting self.name and self.salary, and Manager.details() would have to rebuild the entire earning string from scratch. Using super() keeps the code DRY (Don't Repeat Yourself) and ensures that if Employee's logic changes later, Manager automatically benefits from the update without any changes to its own code.

Method Resolution Order (MRO) โ€” Overriding in Multiple Inheritance

Method overriding becomes considerably more nuanced when a class inherits from multiple parent classes. Python uses an algorithm called C3 linearization to compute a consistent, predictable Method Resolution Order (MRO) โ€” the exact sequence of classes Python checks, in order, when resolving a method call.

๐Ÿ Pythonmro_demo.py
class Base:
    def greet(self):
        return "Hello from Base"

class Left(Base):
    def greet(self):
        return "Hello from Left"

class Right(Base):
    def greet(self):
        return "Hello from Right"

class Child(Left, Right):
    pass   # does not override greet() itself

c = Child()
print(c.greet())          # Hello from Left โ€” Left comes first in MRO
print(Child.__mro__)

Output

Hello from Left (<class 'Child'>, <class 'Left'>, <class 'Right'>, <class 'Base'>, <class 'object'>)

This example demonstrates the classic diamond inheritance pattern: Child inherits from both Left and Right, which both inherit from Base. Since Child itself does not override greet(), Python walks its MRO in order โ€” Child โ†’ Left โ†’ Right โ†’ Base โ†’ object โ€” and stops at the very first class that actually defines greet(), which is Left. Understanding MRO is essential for correctly predicting which overridden method actually runs in complex, multiply-inherited class hierarchies.

Method Overriding vs Method Overloading โ€” Comparison Table

Beginners very frequently confuse overriding with overloading. They sound similar but describe entirely different concepts โ€” and Python handles the second one quite differently from languages like Java or C++.

FeatureMethod OverridingMethod Overloading
DefinitionSubclass redefines a method already in its parentMultiple methods with the same name but different parameters
Relationship requiredRequires inheritance (parent-child classes)Can occur within a single class
When resolvedAt runtime (dynamic dispatch / late binding)At compile time in Java/C++ (static dispatch)
Native Python support?โœ… Fully supported, no special syntax neededโŒ Not natively supported โ€” later definitions silently replace earlier ones
Python workaroundN/A โ€” works nativelyDefault arguments, *args/**kwargs, or functools.singledispatch
PurposeCustomise/specialise inherited behaviourProvide multiple ways to call a function with different argument types/counts
ExampleDog.speak() overriding Animal.speak()area(radius) vs area(length, width) in Java

It's worth emphasising: Python does not support true method overloading the way Java does. If you define two methods with the same name in one class, the second definition simply overwrites the first in the class's namespace โ€” there is no mechanism to have Python choose between them based on argument count or type, unless you explicitly build that logic yourself using default parameters, *args/**kwargs, or the functools.singledispatch / singledispatchmethod decorators.

Method Overriding in Python vs Other Languages

Overriding exists in every mainstream object-oriented language, but the exact rules and required syntax vary considerably. Here's how Python compares to Java and C++.

FeaturePythonJavaC++
Special keyword needed?โŒ No โ€” automatic by name matchโŒ No, but @Override annotation recommendedโœ… Yes โ€” virtual keyword required in base class
Default dispatchDynamic (always runtime resolution)Dynamic for instance methodsStatic, unless virtual is used
Calling the parent versionsuper().method()super.method()BaseClass::method()
Signature must match exactly?Not enforced by the languageโœ… Enforced by compiler with @Overrideโœ… Enforced by compiler
Overriding private methodsN/A โ€” name mangling changes behaviour entirelyโŒ Not possible โ€” private methods aren't inherited-visibleโŒ Not possible โ€” private methods aren't virtual by default
Overriding static/class methodsโœ… classmethod can be overridden like instance methodsโš ๏ธ Static methods are hidden, not overridden (no polymorphism)โš ๏ธ Static methods cannot be virtual

Advantages and Disadvantages of Method Overriding

Method overriding is a powerful and heavily used technique, but it introduces certain risks and trade-offs that are worth understanding before relying on it extensively.

โœ… Advantages
Enables Runtime PolymorphismA single method call can behave differently across many subclasses, letting code work generically with any object in a class hierarchy.
Customises Behaviour Without DuplicationSubclasses only need to override the specific methods that differ, inheriting everything else unchanged from the parent class.
Supports the Open/Closed PrincipleNew subclasses can override behaviour to extend a system without modifying any existing, tested parent class code.
Works Seamlessly with super()Overriding methods can selectively reuse parent logic via super(), striking a balance between customisation and code reuse.
Powers Framework Extension PointsFrameworks like Django, Flask, and unittest are designed around expected overriding, giving developers clean, well-defined hooks for custom behaviour.
โŒ Disadvantages
No Compile-Time Safety NetSince Python has no compiler and no @Override-style check, a typo in a method name silently creates a brand-new method instead of overriding the intended one โ€” with no warning.
Can Break the Liskov Substitution PrincipleIf an override changes a method's expected behaviour too drastically, code written for the parent class may break unexpectedly when given a subclass instance.
Complex MRO in Multiple InheritanceDiamond-shaped or deep multiple-inheritance hierarchies can make it genuinely difficult to predict which overridden method will actually execute without checking __mro__.
Risk of Forgetting super()Overriding __init__ without calling super().__init__() can silently skip essential parent class setup logic, leading to subtle bugs.
Overriding Can Obscure BehaviourDeeply nested override chains across many subclass levels can make it hard to trace exactly which version of a method actually runs without careful investigation.

Method Overriding Architecture โ€” Dispatch Diagram

The diagram below visualises how a single overridden method call travels down through a class hierarchy, showing exactly where Python's dynamic dispatch mechanism intervenes to select the correct implementation.

Calling Code
animal.speak()employee.details()shape.area()
Dynamic Dispatch Engine
type(obj) lookupMRO computation (C3 linearization)__mro__ traversal
Subclass Override Layer
Dog.speak()Manager.details()Circle.area()
super() Bridge
super().speak()super().__init__()Calls next class in MRO
Parent Class Implementation
Animal.speak()Employee.details()Shape.area()

Architecture Diagram

Notice the super() Bridge layer sitting between the subclass override and the parent implementation โ€” this is what allows an override to selectively reach back into the parent's original behaviour instead of either fully replacing it or fully duplicating it.

Where Method Overriding is Used โ€” Real-World Applications

Method overriding shows up constantly in professional Python development in 2026. Here are the major real-world contexts where it plays a central role:

  • โ–ถ

    ๐Ÿ—„๏ธ Django Model save() Overriding โ€” Developers routinely override a Django model's save() method to add custom logic, like automatically generating a slug or timestamp, before calling super().save() to complete the actual database write.

  • โ–ถ

    ๐Ÿ–จ๏ธ Dunder Method Customisation โ€” Nearly every user-defined Python class overrides __str__, __repr__, __eq__, or __lt__ to customise how objects are printed, compared, or sorted, replacing Python's generic default behaviour.

  • โ–ถ

    ๐Ÿงช unittest.TestCase Setup Methods โ€” Test classes override setUp() and tearDown() to define custom test fixtures, while the base TestCase class defines a default (usually empty) implementation as the extension point.

  • โ–ถ

    ๐ŸŒ Flask/Django View Class Overriding โ€” Class-based views override methods like get() and post() to define custom request handling, while inheriting shared dispatch logic from the framework's base View class.

  • โ–ถ

    ๐Ÿค– Machine Learning Custom Layers โ€” In frameworks like PyTorch, custom neural network layers are built by subclassing nn.Module and overriding its forward() method to define the layer's specific computation.

  • โ–ถ

    ๐ŸŽฎ Game Entity Behaviour โ€” A base GameCharacter class might define a generic attack() method, which specific character subclasses (Warrior, Mage, Archer) override with completely different combat mechanics.

  • โ–ถ

    ๐Ÿ”Œ Exception Class Customisation โ€” Custom exception classes commonly override __init__ or __str__ to attach additional context (like an error code) while still calling super().__init__() to preserve standard exception behaviour.

Method Overriding vs Polymorphism โ€” How They Relate

Method overriding and polymorphism are closely linked but not identical โ€” overriding is one specific mechanism that enables the broader concept of polymorphism.

AspectMethod OverridingPolymorphism
Core ideaA subclass redefines a specific inherited methodOne interface, many different behaviours across types
ScopeA relationship between exactly two classes (parent/child)A broader principle spanning inheritance, duck typing, and operator overloading
Is it a mechanism or a concept?A concrete mechanism (technique)A conceptual OOP principle
ExampleDog overrides Animal.speak()A loop calling .speak() on Dog, Cat, and Bird objects, each behaving differently
Can polymorphism exist without overriding?N/Aโœ… Yes โ€” via duck typing or operator overloading, without any shared class hierarchy

In short: overriding is how Python achieves one common form of polymorphism (inheritance-based polymorphism), but polymorphism itself is a broader idea that can also be achieved without any inheritance at all, purely through duck typing.

Why Should You Master Method Overriding in 2026?

Method overriding is a defining topic in nearly every Python OOP interview and shows up constantly in framework-heavy production code. Here's why mastering it deeply matters:

  • โ–ถ

    ๐Ÿ’ผ A Core OOP Interview Topic โ€” Overriding, super(), and MRO are among the most frequently tested Python OOP concepts, especially for roles involving Django, Flask, or any framework-heavy work.

  • โ–ถ

    ๐Ÿ—๏ธ Essential for Working with Frameworks โ€” Nearly every major Python framework โ€” Django, Flask, PyTorch, unittest โ€” is designed around expected method overriding as its primary extension mechanism.

  • โ–ถ

    ๐Ÿ Foundation for Understanding Dunder Methods โ€” Overriding __str__, __eq__, __add__, and other dunder methods is how you customise Python's built-in behaviours for your own classes โ€” a skill used in almost every serious Python project.

  • โ–ถ

    ๐Ÿš€ Key to Writing Extensible, DRY Code โ€” Overriding combined with super() lets you extend behaviour cleanly instead of duplicating logic, directly supporting maintainable, professional-grade software design.

  • โ–ถ

    ๐Ÿ”„ Prevents Subtle, Hard-to-Find Bugs โ€” Understanding MRO and how super() actually works prevents entire categories of bugs that arise from multiple inheritance and diamond-shaped class hierarchies.

Common Method Overriding Mistakes Beginners Make

Even experienced developers occasionally trip up on method overriding. Here are the mistakes that show up most often in real code reviews and beginner projects.

  • โ–ถ

    Forgetting to call super().__init__() โ€” Overriding __init__ without calling the parent's __init__ can silently skip essential setup logic, leaving the object in an incomplete or broken state.

  • โ–ถ

    Mismatched method signatures โ€” Overriding a method with a different number or order of parameters than the parent can break code that calls the method generically across the whole hierarchy, since Python does not check this at all.

  • โ–ถ

    Accidental overriding via typos โ€” Misspelling a method name meant to override a parent's method (e.g. def spek() instead of def speak()) silently creates a brand-new method rather than an override, with no error raised.

  • โ–ถ

    Assuming Python supports overloading โ€” Defining two methods with the same name but different parameters in one class does not create an overload; the second definition simply replaces the first entirely.

  • โ–ถ

    Ignoring MRO in multiple inheritance โ€” Assuming a method call will resolve to a specific parent class without actually checking __mro__ can lead to confusing, hard-to-debug behaviour in diamond-shaped hierarchies.

Method Overriding Interview Questions โ€” Beginner to Intermediate

These are the most frequently asked interview questions on Python method overriding. Master these before any OOP-focused interview.

Practice Questions โ€” Test Your Method Overriding Knowledge

Test your understanding of Python method overriding with these practice questions. Try to answer each one before revealing the answer โ€” active recall is the most effective way to learn.

1. What will happen if a subclass defines a method with a completely different name than any method in its parent class?

Easy

2. Why does Python not require a keyword like Java's @Override for method overriding to work?

Easy

3. What does calling super().method_name() actually do inside an overriding method?

Easy

4. In a diamond inheritance hierarchy where Child inherits from both Left and Right, and both override a shared method from Base, which version runs when Child() calls that method and does not override it itself?

Medium

5. Why is Python's lack of true method overloading not usually considered a major limitation?

Medium

6. Design a Shape base class with an area() method, and a Square subclass that overrides area() but also uses super() to log a message before returning the calculated area.

Medium

7. What subtle bug can occur if an overriding method changes the expected return type of the parent's method (for example, returning a string instead of a number)?

Hard

8. Explain how Python's C3 linearization algorithm ensures a 'monotonic' and consistent MRO even in complex multiple-inheritance hierarchies.

Hard

Conclusion โ€” Mastering Method Overriding in Python

Method overriding is the mechanism that lets inheritance become truly powerful rather than merely a way to copy code. By allowing subclasses to redefine specific behaviour while inheriting everything else unchanged, Python enables the kind of flexible, extensible design seen throughout Django, Flask, PyTorch, and virtually every serious Python framework.

Understanding overriding deeply means going beyond just 'redefining a method' โ€” it means understanding dynamic dispatch, the Method Resolution Order, and how super() lets you extend rather than blindly replace inherited behaviour. These three concepts together form the backbone of professional, maintainable object-oriented Python code.

Your GoalShould You Use Method Overriding Here?
Customising a framework's base class behaviourโœ… Absolutely โ€” this is the intended extension pattern (e.g. Django's save())
Adding subclass-specific logic while keeping shared setupโœ… Yes โ€” override the method and call super() to reuse parent logic
Two methods in one class doing similar things with different argsโš ๏ธ Not overriding โ€” use default arguments or functools.singledispatch instead
Completely unrelated method names between classesโŒ Not overriding at all โ€” this is just independent method definitions
Deep multiple inheritance with shared ancestor methodsโš ๏ธ Proceed carefully โ€” always check __mro__ to confirm resolution order
Customising object printing, comparison, or arithmeticโœ… Yes โ€” override dunder methods like __str__, __eq__, __add__

As a next step, practice by taking one of your own base classes and creating two or three subclasses that override the same method differently โ€” then write a single loop that calls that method polymorphically across all of them. Seeing one line of code produce different, correct behaviour for each subclass is the clearest way to internalise why overriding matters.

Method overriding is what turns a class hierarchy into a living, adaptable system. Master it alongside encapsulation, abstraction, and inheritance, and you will have a complete, professional command of Python's object-oriented foundations. ๐Ÿ”

Frequently Asked Questions (FAQ)