Understanding Polymorphism in Python with Examples
![]() |
| Understanding Polymorphism in Python with Examples |
Understanding Polymorphism in Python with Examples
- Understanding Polymorphism in Python with Examples in object-oriented programming that allows objects of different classes to be treated as objects of a common base class.
- This concept promotes code reusability, flexibility, and abstraction.
- In Python, polymorphism is achieved through method overriding and operator overloading.
- In this article, we will explore polymorphism in Python with examples to understand how it enhances the flexibility and readability of code.
1. Method Overriding:
- Method overriding occurs when a derived class provides a specific implementation for a method that is already defined in its base class.
- This allows objects of the derived class to use the overridden method while maintaining a common interface.
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
def animal_sound(animal):
return animal.speak()
# Example usage
dog = Dog()
cat = Cat()
print(animal_sound(dog)) # Output: Woof!
print(animal_sound(cat)) # Output: Meow!
- In this example, both `Dog` and `Cat` classes inherit from the `Animal` class, and they override the `speak` method to provide their specific implementations.
- The `animal_sound` function demonstrates polymorphism by accepting any object of type `Animal` and calling its `speak` method.
2. Operator Overloading:
- Python allows operators to be overloaded, meaning their behavior can be defined for user-defined objects.
- This enables polymorphic behavior when working with different types of objects using standard operators.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other_point):
return Point(self.x + other_point.x, self.y + other_point.y)
def __str__(self):
return f"({self.x}, {self.y})"
# Example usage
point1 = Point(1, 2)
point2 = Point(3, 4)
point3 = point1 + point2
print(point3) # Output: (4, 6)
- In this example, the `Point` class overloads the `+` operator by implementing the `__add__` method.
- This allows instances of the `Point` class to use the `+` operator for addition, demonstrating polymorphism with operators.
1. Compile-Time (Static) Polymorphism:
- Compile-time polymorphism is achieved through method overloading and operator overloading.
- Method overloading occurs when multiple methods in the same class have the same name but different parameters.
- The correct method to be executed is determined at compile time based on the method signature.
class Calculator:
def add(self, a, b):
return a + b
def add(self, a, b, c):
return a + b + c
calc = Calculator()
result1 = calc.add(1, 2) # Calls the first add method
result2 = calc.add(1, 2, 3) # Calls the second add method
- In this example, the `Calculator` class has two `add` methods with different parameter lists.
- The correct method is selected at compile time based on the number and types of arguments provided.
2. Runtime (Dynamic) Polymorphism:
- Runtime polymorphism is achieved through method overriding.
- This occurs when a subclass provides a specific implementation for a method that is already defined in its superclass.
- The correct method to be executed is determined at runtime based on the actual type of the object.
class Animal:
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
return "Woof!"
class Cat(Animal):
def make_sound(self):
return "Meow!"
def animal_sound(animal):
return animal.make_sound()
# Example usage
dog = Dog()
cat = Cat()
print(animal_sound(dog)) # Output: Woof!
print(animal_sound(cat)) # Output: Meow!
- In this example, the `Animal` class has a method `make_sound`, and both `Dog` and `Cat` classes override this method with their implementations.
- The `animal_sound` function demonstrates polymorphic behavior by accepting objects of different types but treating them uniformly through the common `make_sound` interface.
- Polymorphic behavior enhances code readability, flexibility, and maintainability by allowing code to work seamlessly with objects of different types that share a common interface or base class.
- It promotes the "write once, use anywhere" philosophy, making it easier to extend and adapt code as requirements evolve.
1. Real-world Analogy:
- Think of a real-world analogy, like a remote control.
- Different electronic devices like TVs, DVD players and sound systems all have different implementations of the "power" button. However, from the user's perspective, the "power" button behaves uniformly across devices.
- This is similar to how polymorphism allows objects of different types to be treated uniformly through a common interface.
2. Interface-Based Polymorphism:
- In Python, interfaces are not explicitly defined, but you can achieve interface-based polymorphism by defining classes with methods that serve as interfaces.
- Any class that implements these methods can be treated polymorphically.
class Shape:
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius**2
class Square(Shape):
def __init__(self, side_length):
self.side_length = side_length
def area(self):
return self.side_length**2
- Here, both the `Circle` and `Square` classes implement the `area` method from the common base class `Shape`.
- This allows polymorphic behaviour when calculating the area of different shapes.
def calculate_area(shape):
return shape.area()
circle = Circle(5)
square = Square(4)
print(calculate_area(circle)) # Output: 78.5
print(calculate_area(square)) # Output: 16
3. Operator Overloading for Polymorphism:
- Besides method overriding, polymorphism can also be achieved through operator overloading, allowing objects to respond to operators in a customized way.
class ComplexNumber:
def __init__(self, real, image):
self.real = real
self.image = image
def __add__(self, other):
return ComplexNumber(self.real + other.real, self.imag + other.imag)
def __str__(self):
return f"{self.real} + {self.imag}j"
- Here, the `ComplexNumber` class overloads the `+` operator to perform addition on complex numbers.
num1 = ComplexNumber(2, 3)
num2 = ComplexNumber(1, 4)
result = num1 + num2
print(result) # Output: 3 + 7j
4. Inheritance and Polymorphism:
- Polymorphism is closely tied to inheritance. A subclass can be used wherever its superclass is expected, showcasing polymorphic behaviour.
class Vehicle:
def start_engine(self):
pass
class Car(Vehicle):
def start_engine(self):
return "Car engine started"
class Motorcycle(Vehicle):
def start_engine(self):
return "Motorcycle engine started"
Using polymorphism with inheritance:
def start_vehicle_engine(vehicle):
return vehicle.start_engine()
car = Car()
motorcycle = Motorcycle()
print(start_vehicle_engine(car)) # Output: Car engine started
print(start_vehicle_engine(motorcycle)) # Output: Motorcycle engine started
Conclusion:
- Polymorphic behaviour, whether achieved through method overriding, interface-based design, operator overloading, or inheritance, plays a pivotal role in creating flexible, reusable, and extensible code in Python.
- Understanding and applying polymorphism contribute to writing clean, efficient, and maintainable object-oriented programs.

.png)