Polymorphism is a core concept in object-oriented programming (OOP) that allows objects of different classes to be treated as objects of a common superclass.
It enables a single interface to represent multiple types of objects, thereby promoting code reuse, flexibility, and extensibility.
In Python, polymorphism is achieved through method overriding and duck typing, rather than explicit type declarations.
Here's how polymorphism works in Python:
When a subclass provides a specific implementation of a method that is already defined in its superclass.
class Animal: def sound(self): return "Generic animal sound" class Dog(Animal): def sound(self): return "Woof!" class Cat(Animal): def sound(self): return "Meow!" # Polymorphic behaviour animals = [Dog(), Cat()] for animal in animals: print(animal.sound()) # Output: depends on the type of object: Woof!, Meow!
Although Python does not support function overloading based on the number or types of arguments, it's possible to achieve similar behaviour using default argument values or "*args" and "**kwargs".
class MathOperations: def add(self, x, y): return x + y def add(self, x, y, z): return x + y + z math = MathOperations() print(math.add(2, 3)) # This will raise an error due to method overriding print(math.add(2, 3, 4)) # Output: 9
Duck typing is an approach in Python that focuses on an object's behaviour rather than its type.
class Car: def start(self): return "Car Started" class Bike: def start(self): return "Bike Started" def handle_start(obj): return obj.start() # Polymorphic behaviour car = Car() bike = Bike() print(handle_start(car)) # Output: Car Started print(handle_start(bike)) # Output: Bike Started
Using Abstract Base Classes "ABCs" to define abstract methods that subclasses must implement, allows for polymorphic behaviour across subclasses.
from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod 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): self.side = side def area(self): return self.side ** 2 shapes = [Circle(5), Square(4)] for shape in shapes: print(shape.area()) # Output depends on the type of object: Circle's area, Square's area
class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) v1 = Vector(1, 2) v2 = Vector(3, 4) v3 = v1 + v2 # This will invoke __add__ method of v1 object print((v3.x, v3.y)) # Output: (4, 6)
If an object implements a specific method or set of methods, it can be used interchangeably with other objects that implement the same methods.