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!