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. Polymorphism enables a single interface to handle different data types, allowing flexibility and reducing redundancy in code. This tutorial covers everything you need to know about polymorphism in Python, from basic concepts to advanced techniques, complete with examples and real-world applications.
Polymorphism means "many forms." In Python, polymorphism allows the same function or method to behave differently based on the object or data type calling it. This enables flexibility, as you can use a single interface to interact with multiple types of objects or functions, making code more adaptable and reducing redundancy.
Polymorphism provides several benefits:
Python follows the concept of duck typing, which means that the type or class of an object is less important than the methods it defines. If an object implements the expected methods, it can be used interchangeably with other objects.
class Dog:
def sound(self):
return "Woof!"
class Cat:
def sound(self):
return "Meow!"
def make_sound(animal):
print(animal.sound())
# Usage
dog = Dog()
cat = Cat()
make_sound(dog) # Output: Woof!
make_sound(cat) # Output: Meow!
In this example, both Dog and Cat have a sound method, allowing them to be used interchangeably with the make_sound function.
Method overloading allows multiple methods with the same name but different parameters to coexist. Python does not natively support method overloading, but you can achieve similar behavior by setting default values for parameters.
class MathOperations:
def add(self, a, b, c=0):
return a + b + c
math_op = MathOperations()
print(math_op.add(2, 3)) # Output: 5
print(math_op.add(2, 3, 4)) # Output: 9
In this example, add can take either two or three arguments due to the default value of c.
Method overriding occurs when a child class provides a specific implementation for a method that is already defined in its parent class.
class Animal:
def sound(self):
return "Some sound"
class Dog(Animal):
def sound(self):
return "Woof!"
dog = Dog()
print(dog.sound()) # Output: Woof!
In this example, Dog overrides the sound method from Animal, providing its own specific implementation.
Inheritance enables polymorphism by allowing a child class to inherit methods from its parent class and override them if needed. This allows the same method call to behave differently depending on the object type.
class Animal:
def sound(self):
return "Some sound"
class Dog(Animal):
def sound(self):
return "Woof!"
class Cat(Animal):
def sound(self):
return "Meow!"
animals = [Dog(), Cat()]
for animal in animals:
print(animal.sound())
Woof!
Meow!
Here, sound behaves differently for Dog and Cat objects, showcasing polymorphism through inheritance.
Abstract classes and interfaces define a blueprint for other classes, enforcing a specific method signature that subclasses must implement. Python’s abc module allows you to create abstract classes and methods, supporting polymorphism by ensuring consistent method names 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 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(4, 6)]
for shape in shapes:
print(shape.area())
78.5
24
In this example, Circle and Rectangle implement the area method, allowing them to be used interchangeably in the shapes list.
Python supports operator overloading, which allows you to redefine the behavior of operators (like +, -, *) for custom objects. Operator overloading is achieved by implementing special methods, such as __add__, __sub__, and __mul__.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __str__(self):
return f"({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2
print(p3) # Output: (4, 6)
In this example, + is overloaded for the Point class, allowing you to add two Point objects with the + operator.
In a payment system, different payment methods like credit card and PayPal can have their own implementation of a process_payment method. Polymorphism allows us to handle them through a common interface.
from abc import ABC, abstractmethod
class Payment(ABC):
@abstractmethod
def process_payment(self, amount):
pass
class CreditCardPayment(Payment):
def process_payment(self, amount):
print(f"Processing credit card payment of ${amount}")
class PayPalPayment(Payment):
def process_payment(self, amount):
print(f"Processing PayPal payment of ${amount}")
payments = [CreditCardPayment(), PayPalPayment()]
for payment in payments:
payment.process_payment(100)
Processing credit card payment of $100
Processing PayPal payment of $100
In this example, both CreditCardPayment and PayPalPayment provide their own implementation of process_payment, allowing us to process payments through a single interface.
A common real-world application is calculating the area of different shapes. Polymorphism allows each shape class to implement its own area method.
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 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(4, 6)]
for shape in shapes:
print(f"Area: {shape.area()}")
Area: 78.5
Area: 24
Here, Circle and Rectangle both implement the area method, allowing the same function to calculate the area for each shape.
Polymorphism is a powerful concept in Python that allows a single function, method, or operator to behave differently based on the context. By using polymorphism, you can write flexible, reusable, and cleaner code that adapts to various data types and objects. Python’s support for duck typing, method overloading, method overriding, abstract classes, and operator overloading provides multiple ways to implement polymorphism.
With polymorphism, you can:
Now that you understand polymorphism, try implementing it in your Python projects to enhance flexibility and modularity. Happy coding!