Python Inheritance and Polymorphism
Inheritance lets a new class reuse an old one, and polymorphism lets different classes answer the same method call in their own way.
A Quick Recap
In the Classes and Objects lesson you saw a small example of inheritance. A child class is written with the parent class in brackets. The child gets all the parent's attributes and methods for free.
Example
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def details(self):
return f"{self.name} earns Rs {self.salary}"
class Manager(Employee):
pass
m = Manager("Kamran", 180000)
print(m.details())Kamran earns Rs 180000
Manager has no code of its own, but it still has __init__ and details() because it inherits them from Employee.
Adding and Overriding
A child class becomes useful when it adds new things or changes old ones. Use super() to call the parent's version of a method.
Example
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def yearly_pay(self):
return self.salary * 12
class Manager(Employee):
def __init__(self, name, salary, bonus):
super().__init__(name, salary)
self.bonus = bonus
def yearly_pay(self):
return super().yearly_pay() + self.bonus
e = Employee("Sana", 90000)
m = Manager("Kamran", 180000, 300000)
print(e.yearly_pay())
print(m.yearly_pay())1080000 2460000
The manager's yearly_pay() overrides the parent's method, but it still uses the parent's calculation through super() and only adds the bonus.
Checking Types
| Function | Question it answers |
|---|---|
isinstance(obj, Class) | Is this object made from this class, or one of its children? |
issubclass(Child, Parent) | Does this class inherit from that class? |
type(obj) | Which exact class made this object? |
Using e and m from the example above:
Example
print(isinstance(m, Manager))
print(isinstance(m, Employee))
print(isinstance(e, Manager))
print(issubclass(Manager, Employee))
print(type(m).__name__)True True False True Manager
A manager is an employee, so isinstance(m, Employee) is True. An ordinary employee is not a manager.
Polymorphism
Polymorphism means "many forms". Different classes have a method with the same name, and each one does its own job. Your code calls the method without caring which class it is talking to.
Example
class Cash:
def pay(self, amount):
return f"Paid Rs {amount} in cash"
class Card:
def pay(self, amount):
fee = round(amount * 0.02)
return f"Paid Rs {amount} by card (+ Rs {fee} fee)"
class JazzCash:
def pay(self, amount):
return f"Sent Rs {amount} from mobile wallet"
for method in [Cash(), Card(), JazzCash()]:
print(method.pay(1500))Paid Rs 1500 in cash Paid Rs 1500 by card (+ Rs 30 fee) Sent Rs 1500 from mobile wallet
The loop has one line of code, yet it works with three different payment classes. Adding a fourth payment type later needs no change to the loop.
Python uses duck typing: "if it walks like a duck and quacks like a duck, it is a duck". The three classes above do not share a parent. They only need a pay() method, and that is enough.
Abstract Base Classes
Sometimes you want to force every child class to have a certain method. The abc module lets you create a parent that cannot be used directly.
Example
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return round(3.14159 * self.r ** 2, 2)
shapes = [Rectangle(4, 5), Circle(3)]
for s in shapes:
print(type(s).__name__, s.area())
try:
Shape()
except TypeError as err:
print("Error:", err)Rectangle 20 Circle 28.27 Error: Can't instantiate abstract class Shape without an implementation for abstract method 'area'
If a child class forgets to write area(), Python refuses to create objects from it. This catches mistakes early.
Multiple Inheritance
A class can have more than one parent. Python searches the parents from left to right when it looks for a method. This search order is called the MRO (method resolution order).
Example
class Flyer:
def move(self):
return "flying"
class Swimmer:
def move(self):
return "swimming"
def dive(self):
return "diving deep"
class Duck(Flyer, Swimmer):
pass
d = Duck()
print(d.move())
print(d.dive())
print([c.__name__ for c in Duck.__mro__])flying diving deep ['Duck', 'Flyer', 'Swimmer', 'object']
Multiple inheritance is powerful but can get confusing. For beginners, one parent class is usually enough.
Exercise
Exercise
A Manager class inherits from Employee. m is a Manager object. What does isinstance(m, Employee) return?
