🔷 What is Polymorphism?
Polymorphism is a fundamental concept in Object-Oriented Programming (OOP). It means
"many forms".
In simple terms, polymorphism allows the same function, operator, or method to behave
differently depending on the object or context it's being used with.
🔸 Real-life Analogy
A good real-world example is the "drive()" method of different vehicles:
A Car drives on roads.
A Boat drives on water.
A Plane drives (flies) in the air.
They all have a method called drive(), but they behave differently. That’s polymorphism.
✅ Types of Polymorphism in Python (with Programs)
🔶 1. Duck Typing (Dynamic Typing)
📜 Program:
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
# Function that works with any object that has a 'speak' method
def animal_sound(animal):
print(animal.speak())
# Main Program
dog = Dog()
cat = Cat()
animal_sound(dog)
animal_sound(cat)
💡 Output:
Woof!
Meow!
📝 Explanation:
How Your Code Implements Polymorphism
Here’s the key part:
def animal_sound(animal):
print(animal.speak())
This function accepts any object.
It doesn’t care whether the object is a Dog, Cat, or anything else.
It simply calls animal.speak().
Now consider the classes:
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
Both Dog and Cat have a method named speak().
When animal_sound(dog) is called, Python dynamically binds the method to
Dog.speak().
When animal_sound(cat) is called, Python dynamically binds the method to
Cat.speak().
✅ Output
Woof!
Meow!
✅ Why It’s Polymorphism
Because:
The same function (animal_sound) is used for different types of objects.
Each object responds in a type-specific way to the same method call (speak()).
The exact method that runs is decided at runtime (this is dynamic dispatch).
✅ Type of Polymorphism Used
This is an example of:
Dynamic Polymorphism (runtime polymorphism)
Duck Typing in Python: “If it speaks like a dog or a cat, it is treated as such.”
✅ Summary
Polymorphism allows you to write more generic and reusable code.
In your example, both Dog and Cat are used interchangeably by the animal_sound()
function.
This is possible because they share a common interface (speak() method), even though
they are unrelated by inheritance.
🔶 2. Operator Overloading
📜 Program:
class Book:
def __init__(self, pages):
self.pages = pages
def __add__(self, other):
# When + is used, add pages of both books
return Book(self.pages + other.pages)
def __str__(self):
return f"Total Pages: {self.pages}"
# Main Program
b1 = Book(100)
b2 = Book(150)
b3 = b1 + b2 # Calls __add__ method
print(b3) # Calls __str__ method
💡 Output:
Total Pages: 250
📝 Explanation:
Python’s object-oriented system uses a well-defined set of special methods to define behavior
for common operators.
Here are a few examples:
Operator Special Method Description
+ __add__(self, other) Addition / Overloading +
- __sub__(self, other) Subtraction
* __mul__(self, other) Multiplication
== __eq__(self, other) Equality comparison
< __lt__(self, other) Less-than comparison
str() __str__(self) String conversion for print()
✅ Example in Context
class Book:
def __init__(self, pages):
self.pages = pages
def __add__(self, other):
return Book(self.pages + other.pages)
Now, when you write:
python
CopyEdit
b1 = Book(100)
b2 = Book(150)
b3 = b1 + b2
Python runs:
python
CopyEdit
b3 = b1.__add__(b2)
Which returns a new Book object with 250 pages.
✅ Summary
The + operator automatically maps to the __add__() method.
This is possible because of Python's operator overloading system.
You can redefine how built-in operators behave on custom objects by defining special
methods like __add__, __sub__, __eq__, etc.
The + operator is redefined for Book objects using the __add__() method.
When we use b1 + b2, Python calls __add__() to return a new object.
🔶 3. Method Overriding (Inheritance-based Polymorphism)
📜 Program:
class Animal:
def make_sound(self):
print("Some generic sound")
class Dog(Animal):
def make_sound(self):
print("Bark")
class Cat(Animal):
def make_sound(self):
print("Meow")
# Main Program
animals = [Dog(), Cat(), Animal()]
for a in animals:
a.make_sound()
💡 Output:
Bark
Meow
Some generic sound
📝 Explanation:
The make_sound() method is overridden in Dog and Cat.
Based on the object, the method behaves differently at runtime.
This is runtime polymorphism.
🔶 4. Polymorphism with Common Interface (Abstract Concept)
📜 Program:
class Shape:
def area(self):
# Abstract-like method (not enforced)
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius * self.radius
# Main Program
shapes = [Rectangle(10, 5), Circle(7)]
for shape in shapes:
print("Area:", shape.area())
💡 Output:
Area: 50
Area: 153.86
📝 Explanation:
The method area() is defined in base class and overridden in derived classes.
Using the same method name for different shape types demonstrates polymorphism.
🔚 Summary Table
Type Definition Python Example
Behavior depends on method name, not object
Duck Typing animal_sound(dog)
type
Redefining how operators work for user-defined __add__ in Book
Operator Overloading
objects class
Method Overriding Derived class modifies parent class method make_sound() in Dog
Interface-Based Shared method names with different
area() in Shape c
Polymorphism implementations across unrelated classes