Skip to content
Forge Learn/Object-Oriented Python

Inheritance, Composition & Polymorphism

7 min read

You'll learn to

  • -Create a subclass with `class Child(Parent)` and extend `__init__` with `super()`
  • -Override a parent method and explain what polymorphism buys you
  • -Choose between inheritance ("is-a") and composition ("has-a") for a given design

Inheritance lets one class reuse and extend another class's behavior. It is a powerful tool, and also one that is easy to overuse - this chapter covers the mechanics, then the judgment call of when composition is the better answer.

Basic Inheritance

A class can inherit from another by naming it in parentheses. The child class (subclass) automatically gets every attribute and method of the parent class (superclass), and can add new ones or override existing ones.

A base class and a subclass

This is polymorphism: the same `.speak()` call produces different behavior depending on the actual (runtime) type of the object, without the calling code needing to check "is this a Dog or a Cat?" anywhere. The loop above treats every animal identically and lets each object's own `speak` method decide what happens.

Extending __init__ with super()

If a subclass needs its own `__init__` but still wants the parent's setup logic to run too, `super().__init__(...)` calls the parent's version explicitly instead of duplicating its code.

super().__init__() extending the parent constructor

Overriding a method entirely (like `speak` in the Dog/Cat example) replaces the parent's version. Calling `super().method()` inside the override lets you extend the parent's behavior instead of fully replacing it - useful when the subclass wants to do "everything the parent does, plus a bit more."

Composition: "Has-A" Instead of "Is-A"

Inheritance models an "is-a" relationship: a Dog is an Animal. Composition models a "has-a" relationship: an object holds an instance of another class as an attribute, and delegates to it, rather than inheriting from it. Composition is often the better choice - it is more flexible, and it avoids deep, fragile inheritance chains where changing a base class ripples unpredictably through every subclass.

Composition: a Car has an Engine, rather than a Car being an Engine
  • -Reach for inheritance when a subclass genuinely "is a more specific kind of" the parent, and shares most of its behavior.
  • -Reach for composition when you just need to reuse a piece of functionality, or the relationship is "uses" / "has" rather than "is".
  • -A common piece of real-world advice: "favor composition over inheritance" - inheritance hierarchies deeper than 1-2 levels are a common source of hard-to-follow bugs.
Interview Signal

When would you use composition instead of inheritance?

Weak Answer

"Inheritance is more object-oriented, so I'd usually use that."

Strong Answer

"I'd ask whether the relationship is really 'is-a' or just 'uses/has-a'. A Car isn't a kind of Engine, so making Car inherit from Engine would be wrong - Car should hold an Engine instance and delegate to it. I'd only reach for inheritance when subclasses are genuinely specialized versions of the parent and share most of its behavior."

ScaleDojo Logo
Initializing ScaleDojo