Home ยป Python Polymorphism: A Tutorial

Python Polymorphism: A Tutorial

Polymorphism is a key concept in object-oriented programming (OOP) that allows objects of different classes to be treated as objects of a common super class.

In Python, polymorphism enables the use of a unified interface for objects of different types, making it possible to write more generic and reusable code.

What is Polymorphism?

Polymorphism means “many forms” and refers to the ability of a function, method, or object to behave in multiple ways depending on the context. Python supports two types of polymorphism:

Compile-time Polymorphism (Function Overloading): Python does not directly support this feature, but it can be simulated.
Run-time Polymorphism (Method Overriding): Achieved through inheritance, where child classes can override methods of parent classes.

1. Polymorphism with Functions

You can define a function that can accept different types of objects or arguments, and it will behave differently depending on the object passed.

Example: Polymorphism with Built-in Functions

# Polymorphism with len() function
print(len("Hello"))  # Output: 5 (length of string)
print(len([1, 2, 3, 4, 5]))  # Output: 5 (length of list)
print(len({"name": "Alice", "age": 25}))  # Output: 2 (number of key-value pairs in the dictionary)

In this example, the len() function works with different types (string, list, and dictionary), showing polymorphism in action.

2. Polymorphism with User-defined Functions

You can define your own functions that can operate on different data types, allowing for a more generalized and flexible design.

Example: Polymorphic Function for Different Shapes

# Define a function that calculates the area of different shapes
def area(shape):
    return shape.area()

# Define classes for different shapes
class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius ** 2

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

# Create objects of different shapes
circle = Circle(5)
rectangle = Rectangle(4, 6)

# Call the area function for both shapes
print(area(circle))      # Output: 78.5
print(area(rectangle))   # Output: 24

Here, the area() function works with both Circle and Rectangle objects, even though they are different types. This is an example of polymorphism where the same function works differently for different objects.

3. Polymorphism with Class Methods

In Python, you can implement polymorphism through class inheritance and method overriding. This is known as runtime polymorphism. A method in the parent class can be overridden in the child class, and the appropriate method is called depending on the type of the object.

Example: Polymorphism with Method Overriding

# Parent class
class Animal:
    def speak(self):
        print("The animal makes a sound.")

# Child classes
class Dog(Animal):
    def speak(self):
        print("The dog barks.")

class Cat(Animal):
    def speak(self):
        print("The cat meows.")

# Create objects of different classes
dog = Dog()
cat = Cat()

# Call the speak method for each object
dog.speak()  # Output: The dog barks.
cat.speak()  # Output: The cat meows.

In this example, the speak() method is defined in the Animal class, but both Dog and Cat classes override it to provide their own implementation. When calling speak(), the method appropriate to the object’s class is executed, demonstrating polymorphism.

4. Polymorphism with Inheritance

Polymorphism is closely tied to inheritance, where child classes inherit the properties and behaviors of parent classes but can also override them.

Example: Polymorphism in an Inheritance Hierarchy

# Parent class
class Vehicle:
    def description(self):
        return "This is a vehicle."

# Child class for Car
class Car(Vehicle):
    def description(self):
        return "This is a car."

# Child class for Bike
class Bike(Vehicle):
    def description(self):
        return "This is a bike."

# Function that accepts any vehicle type
def show_description(vehicle):
    print(vehicle.description())

# Create instances of Car and Bike
car = Car()
bike = Bike()

# Call the function with different vehicle types
show_description(car)   # Output: This is a car.
show_description(bike)  # Output: This is a bike.

In this example, the description() method is overridden in both Car and Bike, and the show_description() function demonstrates polymorphism by calling the appropriate method based on the object passed.

5. Polymorphism with Abstract Classes

Polymorphism is often implemented using abstract base classes (ABCs) in Python. An abstract class defines methods that must be implemented by child classes, ensuring polymorphism while enforcing method implementation.

Example: Polymorphism with Abstract Base Class

from abc import ABC, abstractmethod

# Abstract base class
class Animal(ABC):
    @abstractmethod
    def speak(self):
        pass

# Child class Dog implements the abstract method
class Dog(Animal):
    def speak(self):
        return "Woof!"

# Child class Cat implements the abstract method
class Cat(Animal):
    def speak(self):
        return "Meow!"

# Function to demonstrate polymorphism
def animal_speak(animal):
    print(animal.speak())

# Create instances of Dog and Cat
dog = Dog()
cat = Cat()

# Call the polymorphic function
animal_speak(dog)  # Output: Woof!
animal_speak(cat)  # Output: Meow!

Here, the Animal class is abstract, and both Dog and Cat must implement the speak() method. The animal_speak() function demonstrates polymorphism by accepting different subclasses of Animal and calling their respective speak() methods.

6. Polymorphism with Multiple Classes

You can achieve polymorphism across multiple unrelated classes, provided they have methods with the same name. Python’s dynamic nature allows you to use polymorphism without inheritance.

Example: Polymorphism Across Unrelated Classes

class Dog:
    def speak(self):
        return "Woof!"

class Cat:
    def speak(self):
        return "Meow!"

class Cow:
    def speak(self):
        return "Moo!"

# Function that works with different animals
def animal_speak(animal):
    print(animal.speak())

# Create instances of different animals
dog = Dog()
cat = Cat()
cow = Cow()

# Call the polymorphic function
animal_speak(dog)  # Output: Woof!
animal_speak(cat)  # Output: Meow!
animal_speak(cow)  # Output: Moo!

In this example, Dog, Cat, and Cow are unrelated classes, but they all implement the speak() method. The animal_speak() function demonstrates polymorphism by treating different objects with the same interface in a unified way.

7. Polymorphism with Operator Overloading

Python supports operator overloading, which allows you to define custom behavior for operators (like +, -, *, etc.) in user-defined classes.

Example: Polymorphism with Operator Overloading

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # Overload the + operator to add two points
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

# Create two points
p1 = Point(2, 3)
p2 = Point(4, 5)

# Add the two points using the overloaded + operator
result = p1 + p2
print(result)  # Output: Point(6, 8)

In this example, the + operator is overloaded using the __add__() method to add two Point objects. This is a form of polymorphism where the same operator (+) works differently for user-defined objects.

Summary

Polymorphism is the ability of different objects to respond to the same method or function in different ways.
Method Overriding is a common way to achieve polymorphism, where child classes provide their own implementation of a parent class method.
Polymorphism allows for generic functions and methods that can handle objects of different classes, increasing code reusability and flexibility.
Abstract classes and interfaces can enforce polymorphism by requiring child classes to implement certain methods.
Operator overloading is a type of polymorphism where operators behave differently based on the operands.

By mastering polymorphism, you can write more flexible and maintainable Python code that can handle a variety of object types in a unified manner.

You may also like

Leave a Comment

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More