Inheritance lets one class reuse the code of another class. The class that gives its features is the parent class (or base class), and the class that receives them is the child class (or derived class). It saves you from writing the same code again, and it lets you model real relationships, such as a Dog being a kind of Animal. This lesson explains inheritance, super(), method overriding, polymorphism, multilevel and multiple inheritance, with output for every example.
Try every example in our online Python compiler. If you are new to classes, read our lesson on classes and objects first.
A first example
Put the parent class name in brackets after the child class name.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f'{self.name} makes a sound'
class Dog(Animal):
pass
d = Dog('Bruno')
print(d.name)
print(d.speak())Output:
Bruno
Bruno makes a soundDog has no code of its own, but it got the constructor and the speak() method from Animal.
Method overriding
A child class can replace a method that it inherited, by defining a method with the same name.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f'{self.name} makes a sound'
class Dog(Animal):
def speak(self):
return f'{self.name} says Woof'
print(Animal('Generic').speak())
print(Dog('Bruno').speak())Output:
Generic makes a sound
Bruno says WoofPython uses the version in the child class when it exists, and the version in the parent class when it does not.
The super() function
super() gives you access to the parent class. It is most often used in the constructor, so the child class can add its own data and still run the parent’s setup.
class Animal:
def __init__(self, name):
self.name = name
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name)
self.color = color
def speak(self):
return f'{self.name} says Meow'
c = Cat('Kitty', 'white')
print(c.speak(), c.color)Output:
Kitty says Meow whitesuper().__init__(name) runs the Animal constructor, which sets self.name. Then Cat sets its own self.color. If you forget the super() call in a child constructor, the parent’s attributes are never created.
You can also use super() to extend a method instead of replacing it:
class Dog(Animal):
def speak(self):
return f'{self.name} says Woof'
class Puppy(Dog):
def speak(self):
return super().speak() + ' (softly)'
print(Puppy('Tiny').speak())
Tiny says Woof (softly)
Polymorphism
Polymorphism means that the same method call can behave differently for different objects. You can treat different child classes in the same way, and each one does its own thing.
animals = [Animal('Generic'), Dog('Bruno'), Cat('Kitty', 'white')]
for animal in animals:
print(animal.speak())Output:
Generic makes a sound
Bruno says Woof
Kitty says MeowThe loop does not need to know which kind of animal it has. It just calls speak().
isinstance() and issubclass()
d = Dog('Bruno')
print(isinstance(d, Dog))
print(isinstance(d, Animal))
print(isinstance(d, Cat))
print(issubclass(Dog, Animal))Output:
True
True
False
TrueA Dog object is also an Animal, because Dog inherits from Animal. But it is not a Cat.
Types of inheritance
Type | Meaning | Example |
|---|---|---|
Single | One child, one parent | Dog inherits from Animal |
Multilevel | A chain of classes | Puppy inherits from Dog, which inherits from Animal |
Multiple | One child with two or more parents | class C(A, B) |
Hierarchical | Several children of one parent | Dog and Cat both inherit from Animal |
Multiple inheritance and the method resolution order
In Python, a class can have more than one parent. If both parents have a method with the same name, Python follows an order, called the method resolution order (MRO), and uses the first match.
class A:
def hello(self):
return 'A'
class B:
def hello(self):
return 'B'
class C(A, B):
pass
print(C().hello())
print([k.__name__ for k in C.__mro__])Output:
A
['C', 'A', 'B', 'object']Python looks in C first, then A, then B, and finally object, which is the base of every class. Because A comes before B in class C(A, B), C().hello() gives ‘A’. Use multiple inheritance carefully, because it can make code hard to follow.
A practical example: Employee and Manager
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def info(self):
return f'{self.name}: {self.salary}'
class Manager(Employee):
def __init__(self, name, salary, team):
super().__init__(name, salary)
self.team = team
def info(self):
return super().info() + f', team of {len(self.team)}'
m = Manager('Asha', 90000, ['Ravi', 'Meena'])
print(m.info())Output:
Asha: 90000, team of 2Manager reuses the Employee code, and adds a team. Its info() method builds on the parent’s version.
When to use inheritance
Use inheritance when there is a clear “is a” relationship: a Dog is an Animal, and a Manager is an Employee. If the relationship is “has a”, such as a Car has an Engine, store the other object as an attribute instead. This is called composition, and it is often simpler and more flexible.
Common mistakes
- Forgetting
super().__init__()in the child constructor, so the parent attributes are missing. - Passing the wrong arguments to the parent constructor.
- Using inheritance for a “has a” relationship. Use an attribute instead.
- Deep chains of classes, which are hard to understand. Keep hierarchies shallow.
- Overriding a method with different parameters, which breaks code that expects the parent’s version.
Practice questions
- Create a class Shape with a method area() that returns 0, and child classes Rectangle and Circle that override it.
- Create a class Vehicle with a brand, and a child class Car that adds a number of doors, using super().
- Make a list of different shapes, and print the total area with a loop.
- Create a class Person and a class Student that inherits from it and adds a roll number.
- What is the method resolution order of class C(A, B)?
Summary
- A child class inherits the attributes and methods of its parent, and can add or override them.
- super() calls the parent class, and is used in constructors and overridden methods.
- Polymorphism lets you call the same method on different objects.
- Python supports single, multilevel, hierarchical and multiple inheritance, and it uses the MRO to choose a method.
