29. Inheritance in depth — Homework solutions

Solution .py files: exercises/29/homework/solutions/.

Problem 1 — Vehicle and Car

Problem. A Car that inherits describe from Vehicle.

Worked solution.

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

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

class Car(Vehicle):
    def __init__(self, name):
        super().__init__(name)

Car("Beetle").describe()   # Beetle is a vehicle.  (inherited)

Problem 2 — Override

Problem. Car.describe() says "car" instead of "vehicle".

Worked solution. Add to the classes above:

class Car(Vehicle):
    def __init__(self, name):
        super().__init__(name)

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

Vehicle("Cart").describe()   # Cart is a vehicle.
Car("Beetle").describe()     # Beetle is a car.

A Vehicle instance finds the original; a Car instance finds its own version first.

Problem 3 — Extend the parent

Problem. Car.describe() runs the parent's version, then adds a line.

Worked solution.

class Car(Vehicle):
    def __init__(self, name):
        super().__init__(name)

    def describe(self):
        super().describe()
        print("  It has four wheels.")

Car("Beetle").describe()
# Beetle is a vehicle.
#   It has four wheels.

Common mistakes.

  • Calling self.describe() inside describe calls this same method again and recurses forever. Use super().describe() to call the parent's version.

Challenge — Two children

Problem. Bird and Fish both inherit Animal and override move.

Worked solution.

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

    def move(self):
        print(f"{self.name} moves.")

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

    def move(self):
        print(f"{self.name} flies.")

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

    def move(self):
        print(f"{self.name} swims.")

creatures = [Bird("Robin"), Fish("Nemo")]
for c in creatures:
    c.move()
# Robin flies.
# Nemo swims.

Both children define move their own way. Because move is called through the loop variable c, Python dispatches to the correct version based on the actual type of each object.

Done?

You can share behaviour with a base class and specialise it in children — inheriting, overriding, and extending. The last chapter of Part 6 — Designing a small class — asks how to make a class pleasant to use.