๐ Polymorphism in Python ๐#
Polymorphism is an OOP concept where the same interface can lead to different implementations across multiple classes. It allows you to write flexible, extensible code that can handle different object types in a uniform way.
What Is Polymorphism?#
Definition: The ability of objects of different classes to respond to the same function or method call in different ways.
Purpose: Write generalized code that works with diverse objects, without needing type checks or separate logic paths.
Polymorphism with Class Methods#
Example: A speak()
Method in Different Animal Classes#
class Animal:
def speak(self):
return "Some generic sound"
class Dog(Animal):
def speak(self):
return "Bark!"
class Cat(Animal):
def speak(self):
return "Meow!"
def make_sound(animal):
print(animal.speak())
dog = Dog()
cat = Cat()
make_sound(dog) # "Bark!"
make_sound(cat) # "Meow!"
Bark!
Meow!
Key Points
Both
Dog
andCat
share the same method name (speak()
), but each has a distinct implementation.make_sound()
doesnโt care whetheranimal
is aDog
orCat
โit just callsanimal.speak()
.
Polymorphism with Built-In Functions#
Pythonโs built-in functions (e.g., len()
, sum()
) are designed to be polymorphic. You can implement magic methods (a.k.a. dunder methods) in your classes to extend these functionsโ behavior to custom objects.
class CustomList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = CustomList([1, 2, 3, 4])
print(len(my_list)) # 4
4
Key Points
Different classes can implement
len()
to customize howlen()
behaves.Polymorphism ensures
len(obj)
will work regardless of the specific class implementing it, as long aslen()
is provided.
Polymorphism in Inheritance Hierarchies#
Polymorphism commonly appears with inheritance, where child classes override methods defined in a parent class. The calling code doesnโt need to know the childโs typeโjust that it implements the method.
Example: A Geometry Scenario#
class Shape:
def area(self):
raise NotImplementedError("Must be implemented by subclasses")
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * (self.radius**2)
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
shapes = [Circle(5), Rectangle(3, 4)]
for shape in shapes:
print(shape.area()) # Different calculations, same .area() interface
78.53975
12
Key Points
Both
Circle
andRectangle
share the.area()
method name.Looping through
shapes
calls.area()
on each object, returning distinct results based on the shape type.
Polymorphism in Everyday Code#
File Handling
file_object.read()
can be any file-like object (text file, binary file, network stream) but they all support aread()
method.
Collections
for x in collection:
works for lists, sets, dictionaries, and custom iterable classes, thanks to theiter()
protocol.
Operator Overloading
a + b
can mean integer addition, float addition, string concatenation, or even custom vector addition depending on the operandsโ types.
Duck Typing in Python#
Concept: โIf it walks like a duck and quacks like a duck, itโs a duck.โ
Python uses duck typing, meaning if an object implements the required methods or attributes, it can be treated as a โduckโ (or any other type in question).
class Duck:
def quack(self):
return "Quack!"
class Person:
def quack(self):
return "I can do a duck impression!"
def make_it_quack(entity):
print(entity.quack())
d = Duck()
p = Person()
make_it_quack(d) # "Quack!"
make_it_quack(p) # "I can do a duck impression!"
Quack!
I can do a duck impression!
Why Polymorphism Matters#
Code Reuse
Write one function (
make_sound()
,calculate_area()
) that works for various objects.
Flexibility
Add new classes later without modifying existing logic, as long as you respect the expected interface.
Clean Architecture
No โgiant switch statementsโ or type checks neededโobjects handle their own functionality.
Best Practices#
Consistent Method Names
Ensure all classes that participate in a polymorphic operation use the same method name and parameters.
Interfaces & Abstract Base Classes (Optional in Python)
Define an abstract class (using
abc
module) to specify required methods, ensuring all child classes provide them.
Avoid Unnecessary Type Checks
Trust that if an object implements the method, you can call it (duck typing).
Test Each Implementation
Verify that each class correctly fulfills the interfaceโs contract (e.g.,
.area()
returns correct geometry).
With polymorphism, your code remains elegant, extensible, and maintains a consistent interface across multiple class implementations.