29. Inheritance in depth

Chapter 27 touched on inheritance: one class building on another. It is how you avoid writing the same code twice. A Dog and a Cat are both Animals — same name, same way of being described, only differing in the sound they make. Inheritance writes the shared part once.

The base class

Start with a general class. Everything common to the family lives here:

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

    def describe(self):
        print(f"{self.name} is an animal.")

A child class that inherits

Name the parent in parentheses, then call super().__init__() to run the parent's constructor:

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name)   # run Animal's __init__

Dog has no describe of its own, but it inherits from Animal, so a Dog instance finds it there:

rex = Dog("Rex")
rex.describe()    # Rex is an animal.   (inherited from Animal)

Python looks up describe on rex, does not find it, then checks Dog, does not find it there either, and finally finds it on Animal.

Adding behaviour the child alone has

Give the child methods the parent lacks. They are defined on the child class, invisible to the parent and to sibling classes:

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name)

    def fetch(self):
        print(f"{self.name} fetches the ball.")

rex = Dog("Rex")
rex.fetch()       # Rex fetches the ball.

Overriding: replacing a parent method

If the child defines a method with the same name as the parent's, the child's version is found first and wins — this is overriding:

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name)

    def describe(self):
        print(f"{self.name} is a dog.")

rex = Dog("Rex")
rex.describe()    # Rex is a dog.   (Dog's version, not Animal's)

Now Python finds describe on Dog and never looks at Animal.

Calling the parent's version too

Sometimes you want to extend the parent's method, not replace it: do what it does, then add to it. Use super() to call the parent's version:

class Dog(Animal):
    def __init__(self, name):
        super().__init__(name)

    def describe(self):
        super().describe()                   # do the Animal part first
        print("  ...specifically, a dog.")   # then the Dog part

rex = Dog("Rex")
rex.describe()
# Rex is an animal.
#   ...specifically, a dog.

super().describe() runs Animal.describe on this instance, then the Dog-specific line follows. This "call up to the parent" is one of the handiest tools in object-oriented code.

Open exercises/29/01-animals.py. It has Animal and Dog. Add a Cat that inherits from Animal, overrides describe to say it is a cat, and adds a meow method. Make one cat and call both.

Checking types with isinstance

isinstance(obj, ClassName) returns True if obj is an instance of that class or any subclass:

rex = Dog("Rex")
print(isinstance(rex, Dog))      # True
print(isinstance(rex, Animal))   # True  (Dog is a subclass of Animal)

This lets you write code that acts differently depending on what kind of object it has received.

Homework

Homework files are in exercises/29/homework/.

Problem 1 — Vehicle and Car

Open exercises/29/homework/01-vehicle.py. Build a base Vehicle class with __init__(name) and a describe() that prints <name> is a vehicle.. Then build a Car that inherits from it. Make a car and call describe() — it should use the inherited method.

Problem 2 — Override

Open exercises/29/homework/02-override.py. Starting from the Vehicle/Car classes, override describe() on Car to print <name> is a car. instead. Confirm a Vehicle still says "vehicle" and a Car says "car".

Problem 3 — Extend the parent

Open exercises/29/homework/03-extend.py. Override Car.describe() so it first calls super().describe(), then prints an extra line, It has four wheels.. Both lines should appear.

Challenge — Two children

Open exercises/29/homework/04-two-children.py. Build Animal plus two children, Bird and Fish. Each overrides move() to print how it gets around (flies, swims). Make one of each, put them in a list, and loop over it calling move().

Stuck or finished? Open the homework solutions page.