Polymorphism in Python

Polymorphism allows different classes to be treated as if they were instances of the same class. In Python, polymorphism enables a common interface for different types, allowing flexibility in code execution.

Understanding Polymorphism

Polymorphism allows us to use the same method name for different objects, making the code more reusable and easier to manage. This is achieved by defining methods with the same name in multiple classes and invoking them through a common interface.


Examples

1. Method Polymorphism in Different Classes

In this example, we define two different classes, Dog and Cat, both having a method named sound(). Even though the classes are different, we can call the sound() method on each object in a consistent manner.

We achieve this by ensuring that both classes define a method with the same name. When we call the method on different objects, Python dynamically determines which method to execute based on the object’s class.

</>
Copy
class Dog:
    def sound(self):
        return "Woof!"
    
class Cat:
    def sound(self):
        return "Meow!"

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

# Calling the sound method on different objects
print("Dog says:", dog.sound())
print("Cat says:", cat.sound())

Output:

Dog says: Woof!
Cat says: Meow!

Even though we use the same method name sound(), Python automatically calls the correct method depending on the object’s class.

2. Polymorphism with a Common Interface

We can use polymorphism to process multiple objects through a common interface. This makes our code more flexible and scalable.

Here, we define multiple classes with the same method and use a loop to call the method on different objects dynamically.

</>
Copy
class Bird:
    def sound(self):
        return "Chirp!"
    
class Cow:
    def sound(self):
        return "Moo!"

# Creating a list of different animal objects
animals = [Bird(), Cow()]

# Using a loop to call the sound method on each object
for animal in animals:
    print(animal.sound())

Output:

Chirp!
Moo!

Even though Bird and Cow are different classes, we can iterate over a list of objects and call their sound() method without needing to know the specific class of each object.

3. Polymorphism in Inheritance

Polymorphism also works through inheritance. When a child class overrides a method from its parent class, the overridden method is called instead of the parent method.

We create a base class Vehicle and define a method move(). Then, we create two child classes, Car and Bike, which override the move() method with their own implementation.

</>
Copy
class Vehicle:
    def move(self):
        return "Moving..."

class Car(Vehicle):
    def move(self):
        return "Car is driving on the road."

class Bike(Vehicle):
    def move(self):
        return "Bike is riding on the trail."

# Creating instances
car = Car()
bike = Bike()

# Calling the move method on different objects
print(car.move())
print(bike.move())

Output:

Car is driving on the road.
Bike is riding on the trail.

Since the Car and Bike classes override the move() method, their version of the method is called instead of the one defined in Vehicle.

4. Using Polymorphism with Functions

Polymorphism allows us to use functions that work on different objects as long as they have a common method.

Here, we define a function travel() that takes any vehicle and calls its move() method without worrying about the object’s type.

</>
Copy
class Vehicle:
    def move(self):
        return "Moving..."

class Car(Vehicle):
    def move(self):
        return "Car is driving on the road."

class Bike(Vehicle):
    def move(self):
        return "Bike is riding on the trail."

def travel(vehicle):
    print(vehicle.move())

# Creating different vehicle objects
car = Car()
bike = Bike()

# Using the same function to handle different objects
travel(car)
travel(bike)

Output:

Car is driving on the road.
Bike is riding on the trail.

The function travel() works with any object that has a move() method, demonstrating polymorphism.

5. Handling Errors in Polymorphism

If an object does not have the expected method, Python will raise an AttributeError. We can handle this using try-except.

</>
Copy
class Tree:
    pass  # No move method

tree = Tree()

try:
    print(tree.move())
except AttributeError as e:
    print("Error:", e)

Output:

Error: 'Tree' object has no attribute 'move'

Since Tree does not have a move() method, Python raises an error, which we handle using try-except.