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.
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.
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.
An overriding method can still call the parent's original implementation using super(), extending rather than completely replacing existing behaviour.
Frameworks like Django and Flask define base methods specifically expecting subclasses to override them, creating clean extension points for custom logic.
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.
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.
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 owndef 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.
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 8Without 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.
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++.
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++.
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.
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.
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.
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?
Easy2. Why does Python not require a keyword like Java's @Override for method overriding to work?
Easy3. What does calling super().method_name() actually do inside an overriding method?
Easy4. 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?
Medium5. Why is Python's lack of true method overloading not usually considered a major limitation?
Medium6. 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.
Medium7. 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)?
Hard8. Explain how Python's C3 linearization algorithm ensures a 'monotonic' and consistent MRO even in complex multiple-inheritance hierarchies.
HardConclusion โ 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.
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. ๐