Inheritance lets a class borrow attributes and methods from another class. The parent is called the base class, and the child is the derived class. Think of it like genetics — a child inherits traits from their parents.
Single Inheritance
The simplest form. One child, one parent.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "..."
class Dog(Animal): # Dog inherits from Animal
def speak(self):
return f"{self.name} says Woof!"
dog = Dog("Buddy")
print(dog.speak()) # Buddy says Woof!
print(dog.name) # Buddy — inherited from Animal
super() — Calling the Parent
Instead of hardcoding the parent class name, we use super(). It gives us a reference to the parent so we can call its methods.
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # call Animal's __init__
self.breed = breed
Multiple Inheritance and the Diamond Problem
Python allows a class to inherit from multiple parents. This is powerful but can get confusing — especially with the diamond problem.
The diamond problem: if both B and C inherit from A, and D inherits from both B and C — which version of A’s methods does D get?
C3 Linearization (MRO)
Python solves this with C3 linearization — an algorithm that creates a predictable method lookup order. We can inspect it:
class A:
def who(self): return "A"
class B(A):
def who(self): return "B"
class C(A):
def who(self): return "C"
class D(B, C):
pass
print(D().who()) # B — because B comes before C in MRO
print(D.mro()) # [D, B, C, A, object]
The rule is: Python checks the class itself first, then left-to-right through the parents, making sure a parent isn’t visited before all its children.
isinstance and issubclass
print(isinstance(D(), B)) # True — D is a child of B
print(isinstance(D(), A)) # True — D is also a child of A (transitive)
print(issubclass(D, A)) # True — the class D itself is a subclass of A
Mixins
A mixin is a small class meant to be combined with others via multiple inheritance. It adds a specific behavior without being a standalone class.
class JsonMixin:
def to_json(self):
import json
return json.dumps(self.__dict__)
class User(JsonMixin):
def __init__(self, name):
self.name = name
print(User("Manish").to_json()) # {"name": "Manish"}
In simple language, inheritance lets us reuse code by building on existing classes. When multiple parents are involved, Python uses MRO (C3 linearization) to decide which method to call — always predictable, always left-to-right.