Python Tutorial
Inheritance in Python
Inheritance lets a new class reuse and extend an existing one. A SavingsAccount is a BankAccount with interest; an Admin is a User with extra permissions. The new class (child, subclass) inherits the attributes and methods of the existing class (parent, base, superclass) and can add or override behaviour.
This lesson covers single, multilevel, hierarchical and multiple inheritance, super(), method overriding, the Method Resolution Order (MRO), isinstance/issubclass, and mixins.
Single Inheritance and Overriding
class Child(Parent): creates a subclass. The child inherits everything; defining a method with the same name overrides the parent's. Inside the override, super().method() calls the parent version so you extend rather than replace behaviour. Every class ultimately inherits from object.
Types of Inheritance
The common structures:
- Single — one parent:
Dog(Animal). - Multilevel — a chain:
Puppy(Dog),Dog(Animal). - Hierarchical — several children of one parent:
Dog(Animal),Cat(Animal). - Multiple — several parents:
FlyingCar(Car, Aircraft). - Hybrid — a combination of the above.
Multiple Inheritance and the MRO
With several parents, Python searches for attributes in the Method Resolution Order, computed by the C3 linearisation algorithm and visible in Class.__mro__ or Class.mro(). super() follows the MRO, not simply "the parent", which lets cooperative classes each run once even in diamond-shaped hierarchies.
Mixins
A mixin is a small class that adds one capability (serialisation to JSON, logging, comparison) and is designed to be combined with others through multiple inheritance: class Order(JsonMixin, TimestampMixin, Model). Mixins should not have their own __init__ state requirements.
Examples
Single inheritance, overriding and super()
class BankAccount:
def __init__(self, owner, balance=0):
self.owner, self.balance = owner, balance
def describe(self):
return f"{self.owner}: Rs.{self.balance}"
def month_end(self):
pass
class SavingsAccount(BankAccount):
def __init__(self, owner, balance=0, rate=0.04):
super().__init__(owner, balance)
self.rate = rate
def month_end(self): # override
self.balance += round(self.balance * self.rate / 12, 2)
def describe(self): # extend
return super().describe() + f" (savings @ {self.rate:.0%})"
acc = SavingsAccount("Asha", 12000)
acc.month_end()
print(acc.describe())
print(isinstance(acc, BankAccount), issubclass(SavingsAccount, BankAccount))
Asha: Rs.12040.0 (savings @ 4%)
True True
Multilevel and hierarchical inheritance
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "..."
def intro(self):
return f"{self.name} says {self.speak()}"
class Dog(Animal):
def speak(self):
return "Woof"
class Puppy(Dog):
def speak(self):
return super().speak() + " (tiny)"
class Cat(Animal):
def speak(self):
return "Meow"
for pet in [Dog("Rex"), Puppy("Bolt"), Cat("Tom"), Animal("Generic")]:
print(pet.intro())
print([c.__name__ for c in Puppy.__mro__])
Rex says Woof
Bolt says Woof (tiny)
Tom says Meow
Generic says ...
['Puppy', 'Dog', 'Animal', 'object']
Multiple inheritance, the diamond and the MRO
class Base:
def setup(self):
print("Base.setup")
class Logging(Base):
def setup(self):
print("Logging.setup")
super().setup()
class Caching(Base):
def setup(self):
print("Caching.setup")
super().setup()
class Service(Logging, Caching):
def setup(self):
print("Service.setup")
super().setup()
Service().setup()
print([c.__name__ for c in Service.mro()])
Service.setup
Logging.setup
Caching.setup
Base.setup
['Service', 'Logging', 'Caching', 'Base', 'object']
A mixin adding JSON serialisation
import json
class JsonMixin:
def to_json(self):
return json.dumps(vars(self), sort_keys=True)
class Course:
def __init__(self, title, lessons):
self.title, self.lessons = title, lessons
class PublishedCourse(JsonMixin, Course):
pass
print(PublishedCourse("Python", 130).to_json())
{"lessons": 130, "title": "Python"}
Common Mistakes
- Forgetting to call super().__init__() in a subclass constructor.
- Calling Parent.method(self) directly in multiple inheritance, which can run a base class twice; use super().
- Deep inheritance hierarchies that are hard to follow — prefer composition for "has-a" relationships.
- Inheriting just to reuse one helper method.
Key Points to Remember
- class Child(Parent) inherits attributes and methods; overriding replaces them.
- super() calls the next class in the MRO, letting you extend behaviour.
- Python supports single, multilevel, hierarchical, multiple and hybrid inheritance.
- The MRO (Class.__mro__) defines lookup order in multiple inheritance.
- Mixins add focused capabilities through multiple inheritance.
Practice the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.