w3resource

Python Polymorphism: How to implement and use Polymorphism

Introduction to Python Polymorphism

In Core, Python Polymorphism is one of easy concept to understand. Polymorphism definition is that Poly means many and morphos means forms. Polymorphism is a core concept in object-oriented programming that allows objects of different classes to be treated as objects of a common superclass. The main idea behind polymorphism is that the same function or method can behave differently depending on the object it is acting upon.

Let's explore how polymorphism works in Python with examples.

Example 1: Polymorphism with a Common Interface

This example demonstrates polymorphism in Python, where a single function (animal_sound) can operate on different types of objects (Dog and Cat) and execute the appropriate method based on the object's class. The common interface (speak) ensures that all derived classes provide the necessary functionality, while the polymorphic function allows for flexible and dynamic behavior based on the object's specific type.

Code:

# Base class
class Animal:
    def speak(self):
        raise NotImplementedError("Subclasses must implement this method")  # Abstract method

# Derived class 1
class Dog(Animal):
    def speak(self):
        return "Woof!"  # Dog's version of speak

# Derived class 2
class Cat(Animal):
    def speak(self):
        return "Meow!"  # Cat's version of speak

# Function that takes an object of type Animal
def animal_sound(animal):
    return animal.speak()

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

# Calling the function with different types of Animal objects
print(animal_sound(dog))  # Output: Woof!
print(animal_sound(cat))  # Output: Meow!

Explanation:

Base Class (Animal):

  • The Animal class serves as a base class that defines a common interface for all animals.
  • Abstract Method (speak): The speak method is defined but raises a NotImplementedError, indicating that it is meant to be implemented by any subclass that inherits from Animal. This makes speak an abstract method, ensuring that each specific animal class must provide its own implementation.

Derived Classes (Dog and Cat):

  • Dog Class:
    • The Dog class inherits from Animal and provides its own implementation of the speak method. When called, it returns the string "Woof!", representing the sound a dog makes.
  • Cat Class:
    • Similarly, the Cat class inherits from Animal and implements the speak method to return "Meow!", representing the sound a cat makes.

Polymorphic Function (animal_sound):

  • Functionality: The animal_sound function is designed to take an object of type Animal as an argument and call its speak method.
  • Polymorphism in Action: When animal_sound is called with an instance of Dog, it executes the speak method of the Dog class, returning "Woof!". When called with an instance of Cat, it executes the speak method of the Cat class, returning "Meow!".

Object Creation and Method Calls:

  • Instances of Dog and Cat are created using dog = Dog() and cat = Cat().
  • The animal_sound function is then called with these instances:
    • print(animal_sound(dog)) calls the speak method on the Dog instance, resulting in the output "Woof!".
    • print(animal_sound(cat)) calls the speak method on the Cat instance, resulting in the output "Meow!".

Example 2: Polymorphism with a Common Operation

This example illustrates how polymorphism works in Python by using a common operation (area) across different classes (Rectangle and Circle). Each subclass implements the area method specific to its shape, while the “print_area()” function uses this method in a polymorphic way, allowing for dynamic behavior based on the object's type. This approach demonstrates how polymorphism enhances code flexibility and reusability, enabling the same function to operate on different types of objects while producing the correct result based on the object's specific implementation.

Code:

# Base class
class Shape:
    def area(self):
        raise NotImplementedError("Subclasses must implement this method")  # Abstract method

# Derived class 1
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height  # Rectangle's version of area

# Derived class 2
class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * (self.radius ** 2)  # Circle's version of area

# Function that takes an object of type Shape
def print_area(shape):
    print(f"The area is: {shape.area()}")

# Creating instances of Rectangle and Circle
rectangle = Rectangle(7, 10)
circle = Circle(9)

# Calling the function with different types of Shape objects
print_area(rectangle)  # Output: The area is: 70
print_area(circle)     # Output: The area is: 254.34

Explanation:

Base Class (Shape):

  • The Shape class serves as a base class that defines a common interface for all shapes.
  • Abstract Method (area): The area method is defined in the Shape class but raises a NotImplementedError, indicating that it is an abstract method. This method is intended to be overridden by any subclass that inherits from Shape, forcing them to provide a specific implementation of the area calculation.

Derived Classes (Rectangle and Circle):

  • Rectangle Class:
    • The Rectangle class inherits from Shape and provides its own implementation of the area method. It also defines an __init__ method to initialize the width and height attributes.
    • The area method for a rectangle is calculated as width * height, which returns the area of the rectangle.
  • Circle Class:
    • The Circle class also inherits from Shape and implements the area method. It has an __init__ method to initialize the radius attribute.
    • The area method for a circle is calculated as π * radius^2, where π is approximated as 3.14. This formula returns the area of the circle.

Polymorphic Function (print_area):

  • Functionality: The print_area function is designed to take an object of type Shape as an argument and call its area method.
  • Polymorphism in Action: When print_area is called with an instance of Rectangle, it executes the area method of the Rectangle class, calculating the area based on the rectangle's dimensions. Similarly, when called with an instance of Circle, it calculates the area based on the circle's radius.

Object Creation and Method Call:

  • Instances of Rectangle and Circle are created using rectangle = Rectangle(7, 10) and circle = Circle(9).
  • The print_area function is then called with these instances:
    • print_area(rectangle) calls the area method on the Rectangle instance, resulting in the area calculation 7 * 10, which equals 70.
    • print_area(circle) calls the area method on the Circle instance, resulting in the area calculation 3.14 * (9 ** 2), which equals 254.34.

Example 3: Polymorphism with Built-In Functions

This example demonstrates polymorphism in Python using built-in functions like for loops to handle objects of different types in a unified way. Although 'Dog', 'Cat', and 'Cow' are different classes, they all share a common interface ('speak'). This allows the speak method to be called on each object in the 'animals' list without knowing or caring about the object's specific type. Each object responds with its own behavior, showcasing the power of polymorphism to write flexible and reusable code.

Code:

# Example classes with the same interface
class Dog:
    def speak(self):
        return "Woof!"

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

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

# List of objects from different classes
animals = [Dog(), Cat(), Cow()]

# Using a loop to demonstrate polymorphism
for animal in animals:
    print(animal.speak())  # Output: Woof!, Meow!, Moo!

Explanation:

Different Classes with the Same Method (speak):

  • Dog, Cat, and Cow Classes:
    • Each of these classes defines a speak method, but the method returns a different string for each class:
      • Dog.speak() returns "Woof!".
      • Cat.speak() returns "Meow!".
      • Cow.speak() returns "Moo!".
    • These classes do not inherit from a common base class in this example, but they still share a common interface: the speak method. This allows them to be used polymorphically.

Polymorphism with a List:

  • Creating a List of Objects:
    • The list animals contains instances of the Dog, Cat, and Cow classes. These instances are all stored in a single list, despite being of different types.
    • Using a Loop to Demonstrate Polymorphism:
      • A for loop iterates over each object in the animals list.
      • During each iteration, the speak method is called on the current object (animal). Because each object is an instance of a different class, it responds with its own version of speak.
      • The loop outputs:
        • "Woof!" for the Dog instance.
        • "Meow!" for the Cat instance.
        • "Moo!" for the Cow instance.

Example 4: Polymorphism with Inherited Methods

Code:

# Base class
class Vehicle:
    def start(self):
        return "Vehicle is starting"

# Derived class 1
class Car(Vehicle):
    def start(self):
        return "Car is starting"

# Derived class 2
class Motorcycle(Vehicle):
    def start(self):
        return "Motorcycle is starting"

# Function that demonstrates polymorphism
def start_vehicle(vehicle):
    print(vehicle.start())

# Creating instances of Car and Motorcycle
car = Car()
motorcycle = Motorcycle()

# Calling the function with different types of Vehicle objects
start_vehicle(car)        # Output: Car is starting
start_vehicle(motorcycle) # Output: Motorcycle is starting

Explanation:

Base Class (Vehicle):

  • The Vehicle class defines a general method start that returns the string "Vehicle is starting". This method is intended to be shared among all types of vehicles.
  • Common Interface: The start method provides a common interface that all derived classes can use or override.

Derived Classes (Car and Motorcycle):

  • Car Class:
    • Inherits from Vehicle and overrides the start method to return "Car is starting". This provides a specific implementation for starting a car.
  • Motorcycle Class:
    • Also inherits from Vehicle and overrides the start method to return "Motorcycle is starting". This provides a specific implementation for starting a motorcycle.
  • Method Overriding: Both Car and Motorcycle override the start method from the Vehicle class, demonstrating polymorphism. Each class tailors the method's behavior to its own needs while maintaining the same method signature.

Polymorphic Function (start_vehicle):

  • Functionality: The start_vehicle function is designed to accept an object of type Vehicle and call its start method.
  • Polymorphism in Action: The function works polymorphically, meaning it can accept any object that is a subclass of Vehicle (such as Car or Motorcycle) and correctly call the overridden start method for that object.
  • Object Creation and Method Calls:
    • Instances of Car and Motorcycle are created using car = Car() and motorcycle = Motorcycle().
    • The start_vehicle function is then called with these instances:
      • start_vehicle(car) calls the start method on the Car instance, resulting in the output "Car is starting".
      • start_vehicle(motorcycle) calls the start method on the Motorcycle instance, resulting in the output "Motorcycle is starting".

    Summary

    Key Benefits of Polymorphism:

    • Code Flexibility: Allows a single function to work with objects of different types, making the code more adaptable and scalable.
    • Code Reuse: Promotes reuse by allowing shared methods to be customized for specific needs through method overriding.

    Implementation:

    • Polymorphism in Python is typically implemented via method overriding in derived classes. It can be demonstrated using custom functions, loops, or built-in Python functions, providing powerful tools for designing flexible and maintainable object-oriented code.
    

    Become a Patron!

    Follow us on Facebook and Twitter for latest update.