Skip to content

Expert · Object-oriented programming · topic 37 of 50 · 30 min

Inheritance and composition

Explanation

Inheritance lets a new class (the child) reuse and extend an existing class (the parent). The child gets all the parent's methods and can override some of them. Composition is the other way to reuse code: an object holds other objects. Use inheritance for "is a" and composition for "has a".

Reusing a class

A company has employees. Managers are employees too: they have a name and a salary, but also a team and a bonus. Instead of copying the Employee code, we write a Manager class that inherits from Employee. The original class is called the parent (or base) class; the new one is the child (or subclass).

Think of it like this: Think of a family recipe for dal. Your mother uses your grandmother's recipe and adds her own tadka. She did not rewrite the whole recipe; she kept it and changed one step. A child class keeps the parent's code and changes or adds only what is different.
python
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

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

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

class Manager(Employee):                      # Manager inherits from Employee
    def __init__(self, name, salary, team_size):
        super().__init__(name, salary)        # let the parent set name and salary
        self.team_size = team_size

    def describe(self):                       # override the parent's method
        return f"{self.name}, manager of {self.team_size}"

e = Employee("Ravi", 40000)
m = Manager("Sunita", 90000, 6)
print(e.describe())
print(m.describe())
print(m.yearly_pay())    # inherited from Employee: 1080000
Manager did not write yearly_pay(), but it still has it.

super().__init__

super() gives you the parent class. Calling super().__init__(name, salary) runs the parent's setup code, so the child does not repeat it. Then the child adds its own extra attributes.

Careful: If the child has its own __init__ and forgets to call super().__init__(...), the parent's attributes are never set. Later, self.name gives AttributeError.

Overriding and extending

Overriding means the child defines a method with the same name as the parent. Python looks for a method on the child first, then on the parent. You can also extend a method: call the parent version with super() and add to its result.

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

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

class Manager(Employee):
    def __init__(self, name, salary, bonus):
        super().__init__(name, salary)
        self.bonus = bonus

    def yearly_pay(self):
        return super().yearly_pay() + self.bonus   # parent result + extra

print(Manager("Sunita", 90000, 100000).yearly_pay())  # 1180000
Extending keeps the parent's logic in one place.

isinstance: checking the type

python
class Employee: pass
class Manager(Employee): pass

m = Manager()
print(isinstance(m, Manager))    # True
print(isinstance(m, Employee))   # True: a Manager IS an Employee
print(isinstance(Employee(), Manager))  # False
print(issubclass(Manager, Employee))    # True
isinstance also returns True for parent classes.

Composition: "has a"

Inheritance is for "is a" relationships: a Manager is an Employee. When one thing only has another thing, use composition: store the other object as an attribute. A car has an engine; a car is not an engine.

python
class Engine:
    def __init__(self, cc):
        self.cc = cc

    def start(self):
        return f"{self.cc}cc engine started"

class Car:
    def __init__(self, model, cc):
        self.model = model
        self.engine = Engine(cc)     # a Car HAS an Engine

    def start(self):
        return f"{self.model}: " + self.engine.start()

print(Car("Swift", 1197).start())
Car uses Engine without inheriting from it.
QuestionAnswerUse
Is a Manager an Employee?YesInheritance
Is a Car an Engine?No, a Car has an EngineComposition
Is a SavingsAccount a BankAccount?YesInheritance
Is an Order a list of items?No, an Order has itemsComposition
Tip: When you are not sure, prefer composition. Long chains of inheritance (A inherits from B, which inherits from C, which inherits from D) are hard to read and change. One level of inheritance is usually enough.

Watch the lesson

Inheritance and composition · 1/6

Inheritance and composition

In this lesson you will reuse classes with inheritance, and learn when to use composition instead.

Prefer a video by a teacher? Find free videos on “python inheritance super init tutorial” on YouTube ↗

In real life: Vehicles in a transport app

A city transport app shows buses, autos and metro trains. All of them have a number, a route and a fare() method, so they inherit from one Vehicle class. Each one overrides fare() with its own rule: a flat fare for the metro, per-kilometre for autos. Each vehicle also has a GPS tracker object (composition), because a bus is not a GPS tracker.

python
class Vehicle:
    def __init__(self, number):
        self.number = number

    def fare(self, km):
        return 0

class Auto(Vehicle):
    def fare(self, km):
        return 30 + 15 * max(0, km - 1.5)

class Metro(Vehicle):
    def fare(self, km):
        return 20 if km <= 5 else 40

for v in [Auto("MH12 AB 1234"), Metro("Line 3")]:
    print(v.number, v.fare(6))
The same call, v.fare(6), runs a different rule for each type.

Practice (0/3 done)

Task 1 · Code · Python

An Animal class is given. Write a class Dog that inherits from Animal and overrides speak() to return "Woof". Dog should still have the name attribute from Animal.

Task 2 · Code · Python

Employee is given. Write Manager(Employee) with __init__(self, name, salary, bonus) that calls super().__init__(name, salary) and stores bonus. Override yearly_pay() to return the parent's yearly pay plus the bonus.

Task 3 · Code · Python

Use composition. Engine is given. Write a class Car with __init__(self, model, cc) that stores model and creates self.engine = Engine(cc). Add a method start(self) that returns model + ": " + the engine's start() result.

Quick quiz

Question 1

1.In class Manager(Employee):, which is the parent class?

Question 2

2.What does super().__init__(name, salary) do in a child's __init__?

Question 3

3.If m is a Manager and Manager inherits from Employee, what is isinstance(m, Employee)?

Question 4

4.Which relationship fits composition best?

Question 5

5.A child class defines speak() and so does its parent. Which runs for child.speak()?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Classes and objects