Technology  /  Python

🐍 Python 78 guides · updated 2026

From first variable to OOP, generators, and real projects — the language that runs everything from data pipelines to AI agents, taught the practical way.

Method Overriding and super() in Python: Extending Without Replacing

When a subclass defines a method with the same name as a method in its parent class, the subclass version takes precedence. That is method overriding. When you want the subclass to extend the parent’s behaviour rather than replace it entirely, you use super() to call back into the parent. Together, these two tools give subclasses precise control over inherited behaviour.

Method Overriding: The Core Idea

class Notification:
def send(self, message):
print(f"[Notification] {message}")
class EmailNotification(Notification):
def send(self, message):
print(f"[Email] Sending: {message}")
class SMSNotification(Notification):
def send(self, message):
print(f"[SMS] Sending: {message}")
# Each subclass decides what "send" means for it
notifications = [EmailNotification(), SMSNotification(), Notification()]
for n in notifications:
n.send("Your order has shipped")

Output:

[Email] Sending: Your order has shipped
[SMS] Sending: Your order has shipped
[Notification] Your order has shipped

Python looks up the method on the object’s actual class first. If it finds a send method there, it calls that one — the parent’s version is not called automatically.

super(): Extending Rather Than Replacing

Most of the time, you do not want to throw away the parent’s logic — you want to add to it. super() returns a proxy that delegates to the next class in the method resolution order.

class Logger:
def log(self, message):
print(f"[LOG] {message}")
class TimestampLogger(Logger):
def log(self, message):
from datetime import datetime
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Call the parent first, then add our own line
super().log(message)
print(f" Logged at: {timestamp}")
tl = TimestampLogger()
tl.log("Payment processed")
# [LOG] Payment processed
# Logged at: 2025-06-14 09:30:00

You can call super() before or after your own code depending on what makes sense:

super().__init__(): Initialising the Parent

The most common use of super() is inside __init__(). When a subclass has its own attributes, it must still initialise the parent’s attributes.

class Shape:
def __init__(self, colour, filled):
self.colour = colour
self.filled = filled
def describe(self):
fill_str = "filled" if self.filled else "outline"
return f"{fill_str} {self.colour} shape"
class Circle(Shape):
def __init__(self, colour, filled, radius):
super().__init__(colour, filled) # parent gets colour and filled
self.radius = radius # circle adds radius
def area(self):
import math
return math.pi * self.radius ** 2
def describe(self):
base = super().describe()
return f"{base} (circle, r={self.radius})"
c = Circle("blue", True, 5)
print(c.describe()) # filled blue shape (circle, r=5)
print(f"Area: {c.area():.2f}") # Area: 78.54
print(c.colour) # blue — set by Shape.__init__

Without super().__init__(colour, filled), c.colour and c.filled would not exist. Any method inherited from Shape that uses them would crash with an AttributeError.

Override Patterns in Practice

Pattern 1: Complete replacement

Use when the subclass behaviour has nothing in common with the parent.

class Animal:
def sound(self):
return "..."
class Dog(Animal):
def sound(self):
return "Woof" # completely replaces parent
class Cat(Animal):
def sound(self):
return "Meow" # completely replaces parent

Pattern 2: Extension (add before)

Use when the subclass needs to do something before the parent’s logic runs.

class DataProcessor:
def process(self, data):
print(f"Processing {len(data)} records")
return [item.strip() for item in data]
class ValidatingProcessor(DataProcessor):
def process(self, data):
# Validate before processing
if not data:
raise ValueError("Cannot process empty dataset")
return super().process(data) # then hand off to parent

Pattern 3: Wrapping (before and after)

Use for cross-cutting concerns like timing, logging, or transactions.

class DatabaseQuery:
def execute(self, sql):
print(f"Executing: {sql}")
return [] # placeholder
class TimedQuery(DatabaseQuery):
def execute(self, sql):
import time
start = time.perf_counter()
result = super().execute(sql)
elapsed = time.perf_counter() - start
print(f"Query took {elapsed:.4f}s")
return result
tq = TimedQuery()
tq.execute("SELECT * FROM orders WHERE status = 'pending'")

super() in Multiple Inheritance

super() is designed to work with the full method resolution order (MRO), not just one parent. This makes it essential in cooperative multiple inheritance.

class A:
def action(self):
print("A.action")
class B(A):
def action(self):
print("B.action")
super().action() # continues to C in MRO, not directly to A
class C(A):
def action(self):
print("C.action")
super().action()
class D(B, C):
def action(self):
print("D.action")
super().action()
D().action()
# D.action
# B.action
# C.action
# A.action

Python’s MRO for D is D → B → C → A. Each class calls super(), so the chain runs completely. If B did not call super(), C.action and A.action would never run.

Common Mistakes

Calling super() with the wrong arguments (Python 2 style). In Python 3, super() with no arguments works correctly inside a method. The Python 2 form super(ClassName, self) is no longer needed and is error-prone.

# Python 2 style — unnecessary in Python 3
super(Dog, self).__init__(name)
# Python 3 style — just works
super().__init__(name)

Forgetting super() breaks the MRO chain. In multiple inheritance, if any class in the chain fails to call super(), the classes further up the chain do not run. This is a silent bug — no error, just missing behaviour.

Calling the wrong parent directly. Writing ParentClass.method(self) instead of super().method() bypasses Python’s MRO. In single inheritance it looks fine, but in multiple inheritance it causes methods to run twice or not at all.

Using super() outside a class. super() with no arguments only works inside a class definition. Outside, it raises a RuntimeError.