Polymorphism enables writing flexible and reusable code by allowing us to work with objects at a more abstract level, without needing to know their specific types.
There are two main types of polymorphism in object-oriented programming:
Compile-time polymorphism (Static polymorphism)
Runtime polymorphism (Dynamic polymorphism)
Python primarily supports runtime polymorphism, as it is a dynamically typed language. However, we can demonstrate concepts similar to compile-time polymorphism as well.
Let’s explore different aspects of polymorphism in Python:
Python uses duck typing, which is a form of polymorphism. The idea is: “If it walks like a duck and quacks like a duck, then it must be a duck.” In other words, Python cares more about the methods an object has than the type of the object itself.
class Duck:
def speak(self):
return "Quack quack!"
class Dog:
def speak(self):
return "Woof woof!"
class Cat:
def speak(self):
return "Meow meow!"
def animal_sound(animal):
return animal.speak()
# Usage
duck = Duck()
dog = Dog()
cat = Cat()
print(animal_sound(duck)) # Output: Quack quack!
print(animal_sound(dog)) # Output: Woof woof!
print(animal_sound(cat)) # Output: Meow meow!
In this example, animal_sound()
works with any object that has a speak()
method, regardless of its class.
Method overriding is a key aspect of runtime polymorphism. It occurs when a derived class defines a method with the same name as a method in its base class.
class Shape:
def area(self):
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.14159 * self.radius ** 2
# Usage
shapes = [Rectangle(5, 4), Circle(3)]
for shape in shapes:
print(f"Area: {shape.area()}")
# Output:
# Area: 20
# Area: 28.27431
Here, Rectangle
and Circle
both override the area()
method of the Shape
class.
Python allows operator overloading, which is a form of compile-time polymorphism. It allows the same operator to have different meanings depending on the operands.
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)
def __str__(self):
return f"Vector({self.x}, {self.y})"
# Usage
v1 = Vector(2, 3)
v2 = Vector(3, 4)
v3 = v1 + v2
print(v3) # Output: Vector(5, 7)
Here, we’ve overloaded the +
operator for our Vector
class.
Python’s abc
module provides infrastructure for defining abstract base classes, which are a powerful way to define interfaces in Python.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
return "Woof!"
class Cat(Animal):
def make_sound(self):
return "Meow!"
# Usage
def animal_sound(animal):
return animal.make_sound()
dog = Dog()
cat = Cat()
print(animal_sound(dog)) # Output: Woof!
print(animal_sound(cat)) # Output: Meow!
# This will raise a TypeError
# animal = Animal()
Abstract base classes cannot be instantiated and force derived classes to implement certain methods, ensuring a consistent interface.
Polymorphism is widely used in real-world applications:
Here’s a simple example of a plugin system:
class Plugin(ABC):
@abstractmethod
def process(self, data):
pass
class UppercasePlugin(Plugin):
def process(self, data):
return data.upper()
class ReversePlugin(Plugin):
def process(self, data):
return data[::-1]
class Application:
def __init__(self):
self.plugins = []
def add_plugin(self, plugin):
self.plugins.append(plugin)
def process_data(self, data):
for plugin in self.plugins:
data = plugin.process(data)
return data
# Usage
app = Application()
app.add_plugin(UppercasePlugin())
app.add_plugin(ReversePlugin())
result = app.process_data("Hello, World!")
print(result) # Output: !DLROW ,OLLEH
This example demonstrates how polymorphism allows the Application
class to work with different plugins through a common interface.
Cheers for making it this far! I hope this journey through the programming universe has been as fascinating for you as it was for me to write down.
We’re keen to hear your thoughts, so don’t be shy – drop your comments, suggestions, and those bright ideas you’re bound to have.
Also, to delve deeper than these lines, take a stroll through the practical examples we’ve cooked up for you. You’ll find all the code and projects in our GitHub repository learn-software-engineering/examples.
Thanks for being part of this learning community. Keep coding and exploring new territories in this captivating world of software!
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.