Skip to content

Python Inheritance

Updated 8 min read Aimerscrew

Imagine writing a Car class, then a Bike class, then a Truck class, and copying the same brand, year and describe() code into each one. Python inheritance saves you from that. It lets a new class build on an existing one, reusing everything it already does and adding only what's different. In this lesson, you'll create parent and child classes, use super(), override methods, and get a first look at multiple inheritance.

🌍 Real-life example

At a company, every employee has a name, a salary and a way to get paid. A manager is also an employee, so they have all of that too, plus extra things like a team to lead. HR doesn't create a whole new rulebook for managers; it says "a manager is an employee, plus these extras". Inheritance works exactly like that.

What is inheritance in Python?

Inheritance is a way to create a new class from an existing one. The new class automatically gets all the attributes and methods of the original.

  • The original class is the parent class (also called the base class or superclass).
  • The new class is the child class (also called the derived class or subclass).

A good test is the phrase "is a": a car is a vehicle, a manager is an employee. If the sentence makes sense, inheritance is probably a good fit.

How do you create a child class?

Put the parent class name in parentheses after the child's name:

class Vehicle:
    def __init__(self, brand, year):
        self.brand = brand
        self.year = year

    def describe(self):
        print(f"{self.year} {self.brand}")

class Car(Vehicle):
    pass

class Bike(Vehicle):
    pass

family_car = Car("Toyota", 2021)
road_bike = Bike("Trek", 2023)

family_car.describe()
road_bike.describe()
2021 Toyota
2023 Trek

Car and Bike are empty, yet they already have __init__ and describe(), inherited from Vehicle.

Adding new methods to a child class

A child class can add its own methods on top of what it inherits. Those extras belong to the child only:

class Vehicle:
    def __init__(self, brand, year):
        self.brand = brand
        self.year = year

    def describe(self):
        print(f"{self.year} {self.brand}")

class Car(Vehicle):
    def honk(self):
        print(self.brand, "says: Beep beep!")

class Bike(Vehicle):
    def ring_bell(self):
        print(self.brand, "says: Ring ring!")

my_car = Car("Honda", 2020)
my_car.describe()      # inherited from Vehicle
my_car.honk()          # defined in Car

my_bike = Bike("Giant", 2022)
my_bike.ring_bell()
2020 Honda
Honda says: Beep beep!
Giant says: Ring ring!

A Car can't ring_bell(), and a Bike can't honk(). Sibling classes share the parent's features but not each other's.

What is method overriding?

Overriding means writing a method in the child class with the same name as one in the parent. When you call it on a child object, Python uses the child's version.

class Vehicle:
    def __init__(self, brand):
        self.brand = brand

    def start(self):
        print(self.brand, "is starting.")

class ElectricCar(Vehicle):
    def start(self):
        print(self.brand, "starts silently.")

Vehicle("Ford").start()
ElectricCar("Tesla").start()
Ford is starting.
Tesla starts silently.

When you call a method, Python searches the object's own class first, then its parent, then the parent's parent, and uses the first match it finds:

Animation of an inheritance tree: Vehicle at the top with children Car and Bike, and ElectricCar below Car. Calling ev.describe() checks ElectricCar, then Car, then finds describe in Vehicle.
Python looks for a method in the object's class first, then climbs up the family tree until it finds it.

How does super() work in Python?

Often a child needs extra data, but you don't want to rewrite the parent's setup code. The built-in super() function gives you access to the parent class, so you can call its version of a method. The most common use is super().__init__():

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)     # let Employee set name and salary
        self.team_size = team_size         # then add what's new

    def details(self):
        basic = super().details()          # reuse the parent's text
        return f"{basic} and leads {self.team_size} people"

dev = Employee("Priya", 85000)
boss = Manager("Carlos", 120000, 6)

print(dev.details())
print(boss.details())
Priya earns $85,000
Carlos earns $120,000 and leads 6 people

Manager.details() overrides the parent method but still calls super().details() to reuse its work. This "extend, don't replace" pattern keeps your code short and consistent: if Employee changes, Manager picks up the change automatically.

💡 Tip

If your child class has its own __init__, call super().__init__(...) near the top. If the child doesn't define __init__ at all, Python simply uses the parent's, as you saw with the empty Car class.

Multilevel inheritance

A child class can itself be a parent. Each level inherits everything from the levels above it:

class Vehicle:
    def __init__(self, brand):
        self.brand = brand

    def describe(self):
        print("Vehicle made by", self.brand)

class Car(Vehicle):
    wheels = 4

class ElectricCar(Car):
    def charge(self):
        print("Charging the", self.brand)

ev = ElectricCar("Rivian")
ev.describe()       # from Vehicle (two levels up)
print(ev.wheels)    # from Car (one level up)
ev.charge()         # from ElectricCar itself
Vehicle made by Rivian
4
Charging the Rivian

Checking relationships with isinstance() and issubclass()

isinstance(obj, Class) checks whether an object was made from a class or any of its children. issubclass(Child, Parent) checks whether one class inherits from another.

class Vehicle:
    pass

class Car(Vehicle):
    pass

class Bike(Vehicle):
    pass

my_car = Car()

print(isinstance(my_car, Car))
print(isinstance(my_car, Vehicle))
print(isinstance(my_car, Bike))
print(issubclass(Car, Vehicle))
print(issubclass(Vehicle, Car))
print(issubclass(Car, object))
True
True
False
True
False
True

The last line shows something interesting: every class in Python secretly inherits from a built-in class called object. That's where default behavior, like the plain way objects are printed, comes from.

Multiple inheritance and the MRO

Python lets a class inherit from more than one parent by listing them all, separated by commas. The child gets the methods of every parent:

class Swimmer:
    def swim(self):
        print("Paddling through the water")

    def move(self):
        print("Swimming")

class Flyer:
    def fly(self):
        print("Flapping through the sky")

    def move(self):
        print("Flying")

class Duck(Swimmer, Flyer):
    pass

donald = Duck()
donald.swim()
donald.fly()
donald.move()
print([cls.__name__ for cls in Duck.__mro__])
Paddling through the water
Flapping through the sky
Swimming
['Duck', 'Swimmer', 'Flyer', 'object']

Both parents have a move() method, so which one wins? Python follows the Method Resolution Order (MRO): the order in which it searches classes for a name. You can see it in the special __mro__ attribute (or by calling Duck.mro()). Here it's Duck, then Swimmer, then Flyer, then object, so Swimmer.move() wins because Swimmer is listed first.

⚠️ Be careful

Multiple inheritance is powerful but can quickly become confusing. Most everyday code uses single inheritance. Reach for multiple parents only when they add small, independent abilities, like Swimmer and Flyer above.

Common mistakes with inheritance

1. Forgetting to call super().__init__()

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

class Manager(Employee):
    def __init__(self, name, team_size):
        self.team_size = team_size      # forgot super().__init__(name)

boss = Manager("Carlos", 6)
print(boss.name)
AttributeError: 'Manager' object has no attribute 'name'

Defining __init__ in the child replaces the parent's completely. The parent's setup only runs if you call super().__init__(name).

2. Passing self to super()

Write super().__init__(name), not super().__init__(self, name). Just like normal method calls, Python passes self for you. Adding it yourself causes a TypeError about too many arguments.

3. Using inheritance for a "has a" relationship

A car has an engine; it isn't an engine. Don't write class Car(Engine). Instead, store an engine object as an attribute: self.engine = Engine(). Use inheritance only for true "is a" relationships.

Practice exercise

🏋️ Try it yourself

Create a parent class Account with owner and balance and a method info() that returns "Owner: Jo, balance: $500". Then create a child class SavingsAccount that also takes an interest_rate, uses super().__init__(), adds a method add_interest() that increases the balance, and overrides info() to add the rate using super().info().

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

    def info(self):
        return f"Owner: {self.owner}, balance: ${self.balance}"

class SavingsAccount(Account):
    def __init__(self, owner, balance, interest_rate):
        super().__init__(owner, balance)
        self.interest_rate = interest_rate

    def add_interest(self):
        self.balance = self.balance + self.balance * self.interest_rate

    def info(self):
        return f"{super().info()}, rate: {self.interest_rate:.0%}"

savings = SavingsAccount("Jo", 500, 0.04)
print(savings.info())
savings.add_interest()
print(savings.info())
print(isinstance(savings, Account))
Owner: Jo, balance: $500, rate: 4%
Owner: Jo, balance: $520.0, rate: 4%
True

What's next?

You've seen that Vehicle and ElectricCar can both have a start() method that behaves differently. That idea has a name: Python polymorphism. Learn how it lets you write one piece of code that works with many kinds of objects.

Key takeaways

  • Inheritance lets a child class reuse the attributes and methods of a parent class: class Car(Vehicle):.
  • A child class can add new methods and override parent methods by defining a method with the same name.
  • super() gives access to the parent class; super().__init__(...) reuses the parent setup code.
  • Python looks for a method in the object's class first, then climbs up through its parents.
  • isinstance(obj, Parent) is True for objects of child classes; issubclass(Child, Parent) checks class relationships.
  • With multiple inheritance, Python searches classes in the Method Resolution Order (MRO), shown by ClassName.__mro__.
  • Use inheritance for "is a" relationships, not "has a" relationships.

Frequently asked questions

What is inheritance in Python with an example?

Inheritance lets one class reuse another class's code. For example, class Car(Vehicle): creates a Car class that automatically has every attribute and method of Vehicle, and can add its own extras such as honk().

What does super() do in Python?

super() returns a proxy for the parent class so you can call its methods from a child class. The most common use is super().__init__(...) inside the child's __init__ to run the parent's setup code.

What is method overriding in Python?

Method overriding is when a child class defines a method with the same name as a method in its parent. Calls on child objects then use the child's version instead of the parent's.

Does Python support multiple inheritance?

Yes. You can list several parents, like class Duck(Swimmer, Flyer):. When two parents have the same method, Python uses the Method Resolution Order, which generally checks parents from left to right.

What is MRO in Python?

MRO stands for Method Resolution Order. It is the order in which Python searches a class and its parents for an attribute or method. You can view it with ClassName.__mro__ or ClassName.mro().

What are the types of inheritance in Python?

Common forms are single inheritance (one parent), multilevel inheritance (a chain like Vehicle to Car to ElectricCar), hierarchical inheritance (several children of one parent) and multiple inheritance (one child with several parents).