Inheritance

Reuse behaviour by saying 'is a kind of'

Intermediate 11 min

In this lesson

Inheritance lets one class build on another instead of repeating its code. When several types share most of their behaviour but differ in a few details, a parent class can hold the shared parts and each child can add or change just what’s special. This lesson keeps it practical — no deep family trees.

Explain it like I’m 5

Inheritance is like saying a dog is a kind of animal: it gets all the animal basics for free, then adds its own dog-specific behaviour on top.

Parent and child classes, and overriding

You create a child class by naming its parent in parentheses: class Dog(Animal):. The child automatically gets the parent’s attributes and methods. If the child defines a method with the same name as the parent’s, that’s overriding — the child’s version is used for child objects.

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

    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return "Woof"

class Cat(Animal):
    def speak(self):
        return "Meow"

for animal in [Dog("Rex"), Cat("Mia")]:
    print(animal.name, "says", animal.speak())
Output
Rex says Woof
Mia says Meow
Dog and Cat reuse __init__ but override speak().

Extending the parent with super()

Often a child needs to add to the parent’s setup rather than replace it. super().__init__(...) runs the parent’s __init__ first, then the child adds its own extra attributes. This avoids copying the parent’s setup code into every child.

Example
class Account:
    def __init__(self, owner):
        self.owner = owner
        self.balance = 0

class SavingsAccount(Account):
    def __init__(self, owner, rate):
        super().__init__(owner)   # run Account's setup first
        self.rate = rate

s = SavingsAccount("Ada", 0.05)
print(s.owner, s.balance, s.rate)
Output
Ada 0 0.05
super() reuses the parent's setup, then the child adds more.

Common mistake: Forgetting super().__init__() in the child

Why it happens:

The child defines its own __init__ and never calls the parent’s, so the parent’s attributes are never set.

How to fix it:

Call super().__init__(...) at the top of the child’s __init__ so the parent’s setup runs before the child adds its own attributes.

Common mistake: Reaching for inheritance when things are only loosely related

Why it happens:

Inheritance feels powerful, so it gets used to share a single method between classes that aren’t really the same kind of thing.

How to fix it:

Only inherit when the child genuinely is a kind of the parent. For shared bits of behaviour between unrelated types, a helper function or composition (holding another object as an attribute) is usually clearer.

Common mistake: Overriding a method and dropping needed parent behaviour

Why it happens:

A child rewrites a method from scratch and forgets the parent did something important in it.

How to fix it:

If you only want to add to the parent’s behaviour, call super().the_method() inside the override and then do the extra work.

What does super() help you do?

What does method overriding mean?

Why might composition (holding another object) sometimes beat inheritance?

Mini exercise (medium)

Create a Vehicle parent class that stores a name, then Car and Bike child classes that each override describe() — for example "Tesla is a car with 4 wheels" and "BMX is a bike with 2 wheels". Loop over a mixed list of a car and a bike and print each description.

Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.

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

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

class Car(Vehicle):
    def describe(self):
        # TODO: return e.g. "Tesla is a car with 4 wheels"
        return ""

class Bike(Vehicle):
    def describe(self):
        # TODO: return e.g. "BMX is a bike with 2 wheels"
        return ""

for v in [Car("Tesla"), Bike("BMX")]:
    print(v.describe())

What to learn next

You learned how a child class inherits a parent’s attributes and methods, how to override a method, how super() reuses the parent’s setup, and how polymorphism lets the same method name do the right thing for each type. You built Car and Bike classes from a shared Vehicle and looped over a mixed list.

Next you’ll make your objects feel like Python’s own built-in types. Special Methods: Making Objects Feel Pythonic covers __str__, __repr__, __len__, and __eq__ — the hooks that make print(), len(), and == just work. When you’re ready, continue to the next lesson.