Part 4 of 6 · Chapter 4 of 4

Reusing Behaviour Without Copying It

Two classes that share eighty percent of their behaviour usually end up as two copies of that eighty percent. Write the shared part once, inherit it in both, and override only what actually differs.

Intermediate10 min read

Two classes that share eighty percent of their behaviour usually end up as two copies of that eighty percent. Write the shared part once, inherit it in both, and override only what actually differs.

A child class starts with everything the parent has

Terminal
$ >>> class Animal:$ ...     def __init__(self, name):$ ...         self.name = name$ ...     def describe(self):$ ...         return f"{self.name} is an animal"$ ...$ >>> class Dog(Animal):$ ...     pass$ ...$ >>> rex = Dog("Rex")$ >>> rex.describe()$ 'Rex is an animal'

class Dog(Animal): makes Dog a subclass of Animal. Even though Dog defines nothing of its own yet, it already has __init__ and describe, inherited in full.

Overriding a method without touching the original

Define a method with the same name in the subclass, and it replaces the parent's version for that subclass only — Animal itself, and anything else that inherits from it, is untouched.

Terminal
$ >>> class Dog(Animal):$ ...     def describe(self):$ ...         return f"{self.name} is a dog"$ ...$ >>> rex = Dog("Rex")$ >>> rex.describe()$ 'Rex is a dog'

When inheritance is the right tool, and when composition is

Inheritance says this thing is a kind of that thing — a dog is a kind of animal. It fits badly the moment the relationship is really this thing has one of those instead — a car is not a kind of engine, it has an engine. Forcing that second shape into inheritance tends to produce a class hierarchy that fights the problem rather than describing it.

Reach for inheritance

A Dog is an Animal. A SavingsAccount is an Account. The subclass is a more specific version of the same thing.

Reach for composition

A Car has an Engine. An Order has a Customer. Store the other object as an attribute instead of inheriting from it.

Key takeaways

  • class Dog(Animal): makes Dog a subclass that inherits everything Animal defines.
  • Defining a method with the same name in the subclass overrides it there only — the parent class is untouched.
  • Use inheritance when the relationship is "is a kind of", not "has one of".
  • When in doubt, say the relationship out loud. "X is a Y" earns inheritance; "X has a Y" earns a plain attribute.