Skip to content
Laviyx Learn

Try

Python course menu

Python Inheritance: Parent and Child Classes, super() and Method Overriding

Learn inheritance in Python: create child classes that reuse a parent class, override methods, extend __init__ and methods with super(), check relationships with isinstance, and understand multiple inheritance and MRO.

Intermediate9 min readUpdated
On this page

Inheritance lets a new class reuse an existing one. The new child (or subclass) automatically gets everything the parent (or base class) has, and can add new features or change existing ones. It models "is a" relationships: a dog is an animal, a manager is an employee, a savings account is a bank account.

A parent and two children#

Python
class Animal:
    def __init__(self, name):
        self.name = name

    def eat(self):
        return f"{self.name} is eating"

    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return f"{self.name} says woof"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says meow"

d = Dog("Rex")
c = Cat("Tom")
print(d.eat())
print(d.speak())
print(c.speak())
Output
Rex is eating
Rex says woof
Tom says meow
  • class Dog(Animal): means "Dog inherits from Animal".
  • Dog has no __init__ or eat, so it inherits them from Animal.
  • Dog defines its own speak, which overrides the parent's version.

Checking relationships#

Python
print(isinstance(d, Animal), isinstance(d, Cat), issubclass(Dog, Animal))
Output
True False True

A Dog object is also an Animal, so code written for animals works with dogs.

Extending the parent with super()#

Often a child needs everything the parent's method does, plus something extra. super() calls the parent's version:

Python
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

    def annual_pay(self):
        return self.salary * 12

    def describe(self):
        return f"{self.name}: {self.annual_pay()}"

class Manager(Employee):
    def __init__(self, name, salary, team_size):
        super().__init__(name, salary)        # let Employee set name and salary
        self.team_size = team_size            # then add the new attribute

    def annual_pay(self):
        return super().annual_pay() + 5000 * self.team_size

e = Employee("Ravi", 78000)
m = Manager("Priya", 61000, 2)
print(e.describe())
print(m.describe(), m.team_size)
Output
Ravi: 936000
Priya: 742000 2

Notice that describe() is defined only in Employee, yet for Priya it uses Manager's annual_pay(). Python always looks for a method on the actual object's class first.

Forgetting super().init#

If a child defines __init__ and does not call the parent's, the parent's attributes are never set:

Python
class Manager(Employee):
    def __init__(self, name, salary, team_size):
        self.team_size = team_size

m = Manager("Priya", 61000, 2)
print(m.name)
Output
AttributeError: 'Manager' object has no attribute 'name'

Inheritance chains and the MRO#

Classes can inherit from classes that inherit from others. Python searches for methods along the Method Resolution Order (MRO):

Python
class A:
    def hello(self):
        return "A"

class B(A):
    pass

class C(B):
    pass

print(C().hello(), [k.__name__ for k in C.__mro__])
Output
A ['C', 'B', 'A', 'object']

Every class ultimately inherits from object, Python's root class.

Multiple inheritance#

A class can inherit from several parents. This is most often used for small "mixin" classes that each add one capability:

Python
class Swimmer:
    def swim(self):
        return "swimming"

class Flyer:
    def fly(self):
        return "flying"

class Duck(Swimmer, Flyer):
    pass

d = Duck()
print(d.swim(), d.fly())
Output
swimming flying

Use multiple inheritance sparingly. When parents define methods with the same name, the MRO decides which one wins, which can be confusing.

When to use inheritance#

Use it for a genuine "is a" relationship where the child really can be used anywhere the parent is expected. If the relationship is "has a" (a car has an engine), store one object inside another instead. This is called composition, and it is often simpler and more flexible.

Common mistakes#

Practice#

Practice exercise

Given an Account class with owner, balance and a withdraw(amount) method, write a SavingsAccount subclass that adds a rate (default 4%) and an add_interest() method. Create a savings account for Asha with ₹10,000, add interest, then withdraw ₹400.

Show hint

Call super().__init__(owner, balance) in the subclass's __init__, then set self.rate. add_interest increases self.balance by balance * rate.

Show solution
Python
class Account:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("Insufficient funds")
        self.balance -= amount
        return self.balance

class SavingsAccount(Account):
    def __init__(self, owner, balance=0, rate=0.04):
        super().__init__(owner, balance)
        self.rate = rate

    def add_interest(self):
        self.balance += round(self.balance * self.rate, 2)
        return self.balance

s = SavingsAccount("Asha", 10000)
print(s.add_interest())
print(s.withdraw(400))
Output
10400.0
10000.0

withdraw was inherited unchanged from Account, including its insufficient-funds check.

Key takeaway#

Finished this lesson?