The super() Function
Overview
super() gives you access to a parent class's methods from a child class. You'll use it to extend base functionality and avoid code duplication when working with inherited classes, creating more maintainable inheritance hierarchies.
What You Will Learn in This Lesson
By the end of this lesson, you will know:
- What super() is: Understand what the super() function does and why it's useful.
- Calling parent methods: Learn how to call parent class methods from a child class.
- Extending functionality: See how super() helps you extend parent methods instead of replacing them.
- Multiple inheritance: Understand how super() works with multiple parent classes.
- Real-world examples: Practice using super() in practical scenarios.
Understanding super()
When you override a method in a subclass, you completely replace the parent's version. But sometimes, you want to extend the parent method — keep what it does, but add more functionality. That's where super() comes in.
What is super()?
super() is a built-in Python function that gives you access to methods and attributes from a parent class. It's like saying "do what my parent does, then do my own thing too."
Example: Without super()
Imagine you have a parent class that initializes some attributes, and a child class that needs to add more:
class Animal:
def __init__(self, name):
self.name = name
print(f"Animal {self.name} created")
class Dog(Animal):
def __init__(self, name, breed):
self.name = name # Duplicating parent code!
print(f"Animal {self.name} created") # Duplicating parent code!
self.breed = breed
print(f"Dog {self.name} is a {self.breed}")
dog = Dog("Buddy", "Golden Retriever")
This works, but we're duplicating code from the parent class. If the parent class changes, we'd have to update the child class too.
Example: With super()
Now let's use super() to call the parent's __init__ method:
class Animal:
def __init__(self, name):
self.name = name
print(f"Animal {self.name} created")
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # Call parent's __init__
self.breed = breed
print(f"Dog {self.name} is a {self.breed}")
dog = Dog("Buddy", "Golden Retriever")
Much cleaner! The parent class handles its own initialization, and the child class adds its own attributes.
How super() Works
super() returns a temporary object that represents the parent class. When you call a method on it, Python looks up the method in the parent class and executes it.
Syntax
super().method_name(arguments)
Inside a method, super() automatically knows which parent class to use based on the current class.
Try It Yourself
Run this code to see how super() calls the parent method:
What happened?
When you call car.start(), Python first calls the parent's start() method (via super().start()), which prints "Vehicle engine started". Then it continues with the child's code, printing "Car is ready to drive". This is called extending the parent method.
Extending Parent Methods
The most common use of super() is in the __init__ method. When a child class needs to initialize its own attributes, it should first call the parent's __init__ to set up inherited attributes.
Example: Extending __init__
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"Hi, I'm {self.name}, {self.age} years old"
class Student(Person):
def __init__(self, name, age, student_id):
super().__init__(name, age) # Initialize parent attributes
self.student_id = student_id # Add child-specific attribute
def introduce(self):
parent_intro = super().introduce() # Get parent's introduction
return f"{parent_intro}. My student ID is {self.student_id}"
student = Student("Alice", 20, "S12345")
print(student.introduce())
Try It Yourself
Create a Teacher class that extends Person and adds a subject attribute:
super() with Regular Methods
You can use super() with any method, not just __init__. This is useful when you want to add functionality to a parent method without completely replacing it.
Example: Extending a Regular Method
class Shape:
def area(self):
return 0
def describe(self):
return f"This shape has an area of {self.area()}"
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def describe(self):
parent_desc = super().describe() # Get parent's description
return f"{parent_desc}. It's a rectangle with width {self.width} and height {self.height}"
rect = Rectangle(5, 3)
print(rect.describe())
Key Point
Notice that super().describe() calls the parent's describe() method, which in turn calls self.area(). But since self is a Rectangle object, Python uses the overridden area() method from the Rectangle class, not the parent's version. This is polymorphism in action!
super() in Multiple Inheritance
When a class inherits from multiple parents, super() follows Python's Method Resolution Order (MRO) to determine which parent to call. This ensures methods are called in a consistent order.
Example: Multiple Inheritance
class A:
def method(self):
print("A's method")
class B:
def method(self):
print("B's method")
class C(A, B):
def method(self):
super().method() # Calls A's method (first in MRO)
print("C's method")
c = C()
c.method()
Python determines the order based on how classes are listed in the inheritance: class C(A, B) means A comes before B in the MRO.
Note
Multiple inheritance can be complex. For now, focus on single inheritance (one parent class). When you're comfortable with that, you can explore multiple inheritance more deeply.
Common Patterns with super()
Here are some common ways you'll use super() in real code:
Pattern 1: Initialization Chain
class Base:
def __init__(self):
print("Base initialized")
class Middle(Base):
def __init__(self):
super().__init__()
print("Middle initialized")
class Top(Middle):
def __init__(self):
super().__init__()
print("Top initialized")
obj = Top()
This creates a chain: Top → Middle → Base. Each class initializes itself and then calls the parent.
Pattern 2: Adding Validation
class BankAccount:
def __init__(self, balance):
self.balance = balance
def withdraw(self, amount):
self.balance -= amount
return self.balance
class SavingsAccount(BankAccount):
def withdraw(self, amount):
if amount > self.balance:
raise ValueError("Insufficient funds")
return super().withdraw(amount) # Call parent after validation
account = SavingsAccount(100)
print(account.withdraw(50))
print(account.withdraw(60)) # This will raise an error
The child class adds validation, then calls the parent method to do the actual work.
End-of-Lesson Exercises
Complete these exercises to practice using super():
Exercise 1: Extend Animal Class
Create a Cat class that extends Animal. The Cat should call the parent's __init__ using super() and add a color attribute. Then override the make_sound() method to print "Meow" but also call the parent's make_sound() first.
Exercise 2: Extend Employee Class
Create a Manager class that extends Employee. Use super() to call the parent's __init__ and add a team_size attribute. Override the get_info() method to include the team size in the output, but first get the parent's info using super().