Python Polymorphism
Polymorphism means "the same call works on different types". Python takes a relaxed approach — duck typing: if it quacks like a duck, treat it like a duck.
Inheritance polymorphism
PYTHON
class Shape:
def area(self): raise NotImplementedError
class Circle(Shape):
def __init__(self, r): self.r = r
def area(self): return 3.14 * self.r ** 2
class Square(Shape):
def __init__(self, s): self.s = s
def area(self): return self.s * self.s
for sh in [Circle(2), Square(3)]:
print(sh.area())
Duck typing
No inheritance needed — just the right method:
PYTHON
class MockResponse:
def json(self):
return {'ok': True}
def consume(api_response):
data = api_response.json() # works for anything with .json()
print(data)
consume(MockResponse())
Operator polymorphism
+ means add for numbers, concatenate for strings and lists. You can give your own classes the same:
PYTHON
class Vec:
def __init__(self, x, y): self.x, self.y = x, y
def __add__(self, other):
return Vec(self.x + other.x, self.y + other.y)
def __repr__(self):
return f'Vec({self.x}, {self.y})'
print(Vec(1, 2) + Vec(3, 4)) # Vec(4, 6)
Protocols (typing.Protocol)
PYTHON
from typing import Protocol
class HasArea(Protocol):
def area(self) -> float: ...
def total_area(shapes: list[HasArea]) -> float:
return sum(s.area() for s in shapes)
A class doesn't need to inherit from HasArea — just having an area() method makes the type checker happy.
Tip: "Ask forgiveness, not permission" (EAFP) is Pythonic for duck typing. Try the operation; catch the exception if it doesn't fit. Cleaner than checking every type first.
Example
Example
for shape in [
type('Circle', (), {'area': lambda self: 3.14})(),
type('Square', (), {'area': lambda self: 4.0})(),
]:
print(shape.area())
Try it Yourself »
Exercise
Pythonic style that doesn't check types, just calls methods.
typing
Four letters; quack.
Discussion
Loading…