Skip to content
Theory · Classes · lesson 7 of 11

Inheritance and super()

Imagine you already have an "animal" blueprint: a name, a sound and the ability to speak. Now you need a cat blueprint. There is no reason to draw everything again. You can take a copy of the old blueprint and write in the margin: "everything as for an animal, but it speaks differently".

Without that option, code would have to be copied. A cat and a dog, like any animal, have a name and a sound, and they speak in almost the same way. If you copy __init__ and the methods into each class, the same fix will later have to be made in several places. A class can take everything from another class and change only what differs:

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

    def speak(self):
        return f"{self.name} says {self.sound}"


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


print(Animal("Ox").speak())  # Ox says ...
print(Cat("Tom").speak())  # Tom purrs

Inheritance

The line class Cat(Animal) means inheritance: Cat is the child class, and Animal is the parent class. The child class gets all the methods and attributes of the parent class.

Let's take apart what happens on the call Cat("Tom"):

  1. Cat has no __init__ of its own, so Python takes the __init__ of Animal.
  2. That __init__ creates the cat's attributes name and sound.
  3. Cat("Tom").speak() calls the speak of Cat and returns "Tom purrs".

Overriding a method

Python looks for a method first in the instance's class, then in the parent class. The speak method of Cat overrides the parent's method: for a cat, that one is found.

So one and the same call works with objects of different classes, and each object runs its own method:

Python
pets = [Animal("Ox"), Cat("Tom")]
print([pet.speak() for pet in pets])  # ['Ox says ...', 'Tom purrs']
print(isinstance(pets[1], Animal), isinstance(pets[0], Cat))  # True False

An instance of a child class also counts as an instance of the parent class: isinstance(pets[1], Animal) gives True. The reverse is false: Animal("Ox") is not a Cat.

The code that calls pet.speak() does not check the pet's class: a new class of animal needs only its own speak method. In interviews this is called polymorphism: one call, with behavior that depends on the object's class.

Calling super()

If a child class needs its own __init__, that method replaces the parent's __init__ entirely: Python itself calls only the child's __init__. For the parent's code to run as well, it is called through super():

Python
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed
        self.sound = "woof"


rex = Dog("Rex", "husky")
print(rex.speak(), rex.breed)  # Rex says woof husky

Let's go through the __init__ of Dog line by line:

  1. super().__init__(name) runs the __init__ of Animal for the same self: rex gets name and a sound holding "...".
  2. self.breed = breed adds the breed.
  3. self.sound = "woof" replaces the sound.

The last assignment wins: if sound is set before the super() call, the parent's __init__ writes "..." into it again. Other parent methods are called through super() too: super().speak() inside a Dog method returns the text of the Animal method.

This is where the blueprint-copy analogy stops working. A child class does not copy the parent's methods into itself. It keeps a link to the parent, and Python looks for a method along the chain each time: first in Dog, then in Animal.

Common mistake

A child's __init__ forgets to call super().__init__():

Python
class Bird(Animal):
    def __init__(self, name):
        self.sound = "tweet"  # ✗


print(Bird("Kiwi").speak())
TEXT
AttributeError: 'Bird' object has no attribute 'name'

The child's own __init__ replaced the parent's, and the line that sets self.name never ran. If the parent has an __init__ of its own, make super().__init__(name) the first line of the child's __init__.

Key points

  • class Cat(Animal) is inheritance: the child class gets the parent's methods and attributes.
  • A method with the same name in the child class overrides the parent's method.
  • An __init__ of its own replaces the parent's entirely, so the parent's code is called through super().__init__(...).
  • An instance of a child class is also an instance of the parent class: isinstance gives True.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way