Python Polymorphism

Python Polymorphism

Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows one method or operator to work in different ways depending on the type of object it is acting upon. The term comes from Greek, meaning “many shapes.” In Python, polymorphism is achieved through method overriding and method overloading.

Types of Polymorphism in Python:

  1. Method Overriding (Runtime Polymorphism)
  2. Method Overloading (Compile-time Polymorphism, not directly supported in Python)
  3. Operator Overloading

1. Method Overriding (Runtime Polymorphism)

Method overriding occurs when a child class provides a specific implementation for a method that is already defined in its parent class. The method in the child class has the same name and signature as the method in the parent class, but the implementation can be different. This allows the child class to provide its own behavior while maintaining the interface defined in the parent class.

Example of Method Overriding:

class Animal:
    def speak(self):
        print("Animal speaks")

class Dog(Animal):
    def speak(self):
        print("Dog barks")

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

# Create objects
animals = [Dog(), Cat()]

# Iterate over the list and call the speak method
for animal in animals:
    animal.speak()  # This demonstrates polymorphism

Output:

Dog barks
Cat meows

In this example:

  • Both Dog and Cat classes override the speak() method from the Animal class.
  • The correct speak() method is called based on the type of object, even though the method call animal.speak() is the same. This is runtime polymorphism because the method that gets executed depends on the object type at runtime.

2. Method Overloading (Compile-time Polymorphism)

In languages like C++ and Java, method overloading allows you to define multiple methods with the same name but with different parameters (different types or a different number of arguments). However, Python does not directly support method overloading in the same way.

In Python, you can achieve method overloading behavior by using default arguments or variable-length arguments (*args and **kwargs), but it does not provide strict compile-time overloading.

Example of Overloading Using Default Arguments:

class Calculator:
    def add(self, a, b=0):
        return a + b

# Create an object of Calculator
calc = Calculator()

# Calling add with one argument (default b=0)
print(calc.add(10))  # Output: 10

# Calling add with two arguments
print(calc.add(10, 5))  # Output: 15

Example of Overloading Using *args:

class Calculator:
    def add(self, *args):
        return sum(args)

# Create an object of Calculator
calc = Calculator()

# Calling add with variable arguments
print(calc.add(10))         # Output: 10
print(calc.add(10, 5))      # Output: 15
print(calc.add(1, 2, 3, 4))  # Output: 10

In these examples:

  • The add method can handle different numbers of arguments, simulating method overloading.

3. Operator Overloading

Operator overloading allows you to define the behavior of operators (like +, -, *, etc.) for user-defined classes. By overriding special methods, you can change how operators work with objects of your custom class.

For example, you can override the __add__ method to define how the + operator behaves when used with instances of a class.

Example of Operator Overloading:

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

    # Overload the + operator to add two Point objects
    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 Point objects
p1 = Point(1, 2)
p2 = Point(3, 4)

# Use the overloaded + operator
p3 = p1 + p2  # This calls p1.__add__(p2)

print(p3)  # Output: Point(4, 6)

In this example:

  • The __add__ method is overridden to allow the addition of two Point objects using the + operator.
  • The result of p1 + p2 is a new Point object with the coordinates (4, 6).

4. Polymorphism with Built-in Functions

Python also allows polymorphism to occur in the context of built-in functions, especially when functions accept various types of arguments. For instance, the len() function can be used to calculate the length of a string, list, tuple, or dictionary, and it works differently depending on the type of object passed.

Example with len():

print(len("hello"))  # Output: 5 (String length)
print(len([1, 2, 3]))  # Output: 3 (List length)
print(len((1, 2, 3)))  # Output: 3 (Tuple length)
print(len({"a": 1, "b": 2}))  # Output: 2 (Dictionary length)

The len() function works with different types of objects, demonstrating polymorphism in action.

5. Polymorphism in Inheritance

When using inheritance, polymorphism allows you to call the same method on objects of different classes, with each class providing a different implementation of that method. This is known as dynamic polymorphism.

Example of Polymorphism in Inheritance:

class Animal:
    def sound(self):
        print("Some generic animal sound")

class Dog(Animal):
    def sound(self):
        print("Bark")

class Cat(Animal):
    def sound(self):
        print("Meow")

def make_sound(animal):
    animal.sound()  # Polymorphic behavior

# Create objects
dog = Dog()
cat = Cat()

# Call the same function with different object types
make_sound(dog)  # Output: Bark
make_sound(cat)  # Output: Meow

In this example:

  • The make_sound function takes an Animal object but behaves differently depending on whether it’s a Dog or Cat object.
  • This shows how polymorphism allows the same function to handle different types of objects and execute different code.

Summary of Polymorphism in Python:

  1. Method Overriding: Allows child classes to provide their own implementation of a method defined in the parent class.
  2. Method Overloading: Python doesn’t directly support method overloading, but you can simulate it using default arguments or variable-length arguments (*args).
  3. Operator Overloading: You can change the behavior of operators for custom classes by defining special methods like __add__, __sub__, etc.
  4. Polymorphism in Inheritance: The ability for objects of different classes to be treated as objects of a common parent class, but with each class providing its own implementation of methods.

Polymorphism allows for more flexible and reusable code by letting you define methods in a generic way while enabling different implementations for different objects.

Leave a Reply 0

Your email address will not be published. Required fields are marked *