Inheritance In Python — PBA Institute Tutorial
Chapter 19 · Python Programming Series
12 min read Beginner

Reusing Code With Inheritance

Inheritance lets one class reuse and extend another. Instead of copy-pasting common code, you say 'this is a kind of that' and let Python wire up the methods automatically. This chapter covers single, multiple, multi-level, and hierarchical inheritance, the powerful super() call, and the MRO that determines who answers a method call.

Overview

♻️

Code Reuse

Avoid duplicating logic — define it once in the parent.

🧬

Extensible

Subclasses can add or refine behaviour without touching the parent.

🎚️

Override Friendly

Customise specific methods while inheriting the rest.

🌳

Hierarchies

Model real-world classifications like Vehicle → Car → ElectricCar.

🧭

MRO Clarity

Python's deterministic lookup order keeps multiple inheritance predictable.

Syntax

  • Subclass: class Child(Parent):.
  • Multiple inheritance: class Z(A, B):.
  • Call parent methods with super().method().
  • Override a method by redefining it in the subclass.
Inheritance — Syntax
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return "generic sound"

class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

class Puppy(Dog):
    def speak(self):
        return f"{self.name} says yip!"

print(Puppy("Bruno").speak())

Detailed Explanation

  • Single inheritance: One subclass, one parent. The simplest and most common form. Example: class Manager(Employee).
  • Multi-level inheritance: A chain: Grandparent → Parent → Child. Each level adds or refines behaviour.
  • Multiple inheritance: A class with two or more parents. Use carefully — Python's MRO (Method Resolution Order) determines which parent's method wins.
  • Hierarchical inheritance: One parent, many subclasses (e.g. Shape → Square, Circle, Triangle).
  • super(): Calls the next class in the MRO. Use it to invoke parent constructors or extend parent methods cleanly.
  • MRO: Python uses C3 linearisation to compute method lookup order. Access via ClassName.__mro__ or ClassName.mro().

Code Examples

Example 1 — Single Inheritance
class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        return "?"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow"

print(Cat("Mittens").speak())
Output Mittens says Meow
Example 2 — Multi-Level Inheritance
class A:
    def hello(self): return "A"
class B(A):
    def hello(self): return "B" + super().hello()
class C(B):
    def hello(self): return "C" + super().hello()

print(C().hello())
Output CBA
Example 3 — Multiple Inheritance
class Walker:
    def move(self): return "walking"

class Swimmer:
    def move(self): return "swimming"

class Duck(Walker, Swimmer):
    pass

print(Duck().move())
print(Duck.__mro__)
Output walking
(<class 'Duck'>, <class 'Walker'>, <class 'Swimmer'>, <class 'object'>)
Example 4 — Hierarchical Inheritance
class Shape:
    def area(self): return 0

class Square(Shape):
    def __init__(self, s): self.s = s
    def area(self): return self.s ** 2

class Circle(Shape):
    def __init__(self, r): self.r = r
    def area(self): return 3.14 * self.r ** 2

for sh in [Square(4), Circle(3)]:
    print(sh.area())
Output 16
28.26
Example 5 — Using super() in __init__
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary

class Manager(Employee):
    def __init__(self, name, salary, team):
        super().__init__(name, salary)
        self.team = team

m = Manager("Riya", 80000, "Backend")
print(m.name, m.team)
Output Riya Backend
Example 6 — Checking with isinstance / issubclass
class Animal: pass
class Dog(Animal): pass
d = Dog()
print(isinstance(d, Dog))
print(isinstance(d, Animal))
print(issubclass(Dog, Animal))
Output True
True
True

Real-World Use Cases

Taxonomies

Biological hierarchies — Animal → Mammal → Dog.

GUI Toolkits

Widget → Button, Widget → Slider, Widget → Label.

ORM Models

Django's Model base class is inherited by every table model.

Vehicles

Vehicle → Car → ElectricCar, sharing common engine/wheels behaviour.

Exception Hierarchies

ValueError and TypeError inherit from Exception.

Mixins

Reuse small features (e.g. LoggableMixin, JsonMixin) across many classes.

Notes & Pro Tips

  • Use inheritance for is-a relationships, composition for has-a.
  • Avoid deep hierarchies (more than 3 levels) — they get hard to follow.
  • Always call super().__init__() in subclass constructors.
  • Prefer mixins or composition over multiple inheritance when possible.
  • Use isinstance(obj, ClassOrTuple) rather than type(obj) == Class — it respects inheritance.
  • Check the MRO with Class.mro() when methods don't behave as expected.

Common Mistakes

  • Diamond ambiguity: in multiple inheritance Python uses MRO; learn it to avoid surprises.
  • Forgetting super(): skipping parent init leaves attributes unset.
  • Overriding without intent: accidentally hiding parent behaviour.
  • Tightly coupled hierarchies: changing the parent breaks many subclasses.
  • Misusing inheritance for code reuse: when there's no 'is-a', composition is better.
  • Using type() for checks: doesn't recognise subclasses; prefer isinstance.

Practice Problems

  • Problem 1: Model a base Vehicle and subclasses Car and Bike.
  • Problem 2: Create AnimalBirdEagle with overridden speak() methods.
  • Problem 3: Demonstrate multiple inheritance with a Swimmer and Flyer mixed into Duck.
  • Problem 4: Implement an Employee base class and subclasses Manager and Developer with overridden bonus().
  • Problem 5: Create a Shape hierarchy with area() implemented differently for square, circle, triangle.
  • Problem 6: Build a logging mixin and use it with two unrelated classes.

Interview Questions

  • Q1. What is inheritance?
  • Q2. What is the difference between single, multi-level and multiple inheritance?
  • Q3. What is the MRO and how does Python compute it?
  • Q4. When should you use inheritance vs composition?
  • Q5. Why must you call super().__init__() in subclasses?
  • Q6. Why is multiple inheritance considered risky?

Frequently Asked Questions

  • Q1: Does Python support multiple inheritance?
    Yes. A class can inherit from more than one parent, and Python uses the C3 MRO to determine method lookup order.
  • Q2: What is the MRO?
    The Method Resolution Order — the deterministic sequence Python uses to look up attributes and methods through the inheritance chain. View it with ClassName.__mro__.
  • Q3: What is the diamond problem?
    When two parents share a common grandparent, calling super() can revisit the grandparent multiple times. Python's MRO solves it by linearising the hierarchy.
  • Q4: Is composition better than inheritance?
    Often, yes — composition is more flexible and less coupled. Use inheritance only when there's a true 'is-a' relationship.
  • Q5: Can a class inherit from itself?
    No — that would be infinite recursion. Python forbids it at class-creation time.
  • Q6: How do I check if X is a subclass of Y?
    Use issubclass(X, Y). For instance checks, use isinstance(obj, Y).

Summary

Inheritance is one of OOP's most powerful tools — done right, it eliminates duplication and creates clear taxonomies. Use it for true is-a relationships, keep hierarchies shallow, prefer composition or mixins when behaviour varies orthogonally, and let super() and the MRO do the heavy lifting. Then your class design will scale gracefully as your codebase grows.

Continue Learning

Previous

Go to Previous Chapter

Next

Go to Next Chapter