Skip to main content

Inheritance and Polymorphism

Inheritance lets a class reuse and extend another class.

inheritance.py
class Shape:
def area(self):
raise NotImplementedError

def describe(self):
return f"{type(self).__name__} with area {self.area():.2f}"


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 3.14159 * self.r ** 2


for shape in [Rectangle(2, 3), Circle(1)]:
print(shape.describe()) # polymorphism: same call, different behaviour

super()​

super.py
class Square(Rectangle):
def __init__(self, side):
super().__init__(side, side)

Composition over inheritance​

Prefer "has-a" relationships when the classes are not truly "is-a".

composition.py
class Engine:
def start(self):
return "vroom"

class Car:
def __init__(self):
self.engine = Engine() # a Car has an Engine

def start(self):
return self.engine.start()

Duck typing​

Python cares about what an object can do, not its declared type: if it has an area() method it can be used where a shape is expected.