Polymorphism in Python

Polymorphism is one of the core concepts of Object-Oriented Programming (OOP) that allows different classes to be treated as if they are objects of the same class through a common interface. The term polymorphism literally means “many forms.”

In simple terms, it allows you to use a single function, method, or operator to behave differently based on the type of object it acts upon.

Understanding Polymorphism

In Python, polymorphism is achieved through dynamic typing — meaning you don't need to explicitly declare types. A function can accept different kinds of objects and behave appropriately based on their type.

Example:

class Dog:
    def sound(self):
        return "Bark"

class Cat:
    def sound(self):
        return "Meow"

# Common interface
def make_sound(animal):
    print(animal.sound())

dog = Dog()
cat = Cat()

make_sound(dog)
make_sound(cat)
Output:

Bark
Meow
Here, both Dog and Cat have a sound() method, but the implementation differs. The function make_sound() works for both — that's polymorphism in action!

Duck Typing in Python

Duck typing is a concept closely related to polymorphism. The idea comes from the phrase: "If it walks like a duck and quacks like a duck, it's a duck."

This means Python doesn't care about an object's class, only about whether it has the required behavior (methods/attributes).

Example:

class Duck:
    def talk(self):
        print("Quack, Quack!")

class Human:
    def talk(self):
        print("Hello there!")

def call_talk(obj):
    obj.talk()  # Doesn't matter what obj is, as long as it has talk()

duck = Duck()
person = Human()

call_talk(duck)
call_talk(person)
Output:

Quack, Quack!
Hello there!
Here, Duck and Human are completely different classes, but since both define a talk() method, the same function can call them — demonstrating duck typing.

Method Overriding

Method overriding occurs when a derived (child) class defines a method with the same name as one in its base (parent) class, but with a different implementation. This allows subclasses to provide their own version of a method.

Example:

class Vehicle:
    def start(self):
        print("Starting the vehicle...")

class Car(Vehicle):
    def start(self):
        print("Starting the car engine...")

v = Vehicle()
v.start()

c = Car()
c.start()
Output:

Starting the vehicle...
Starting the car engine...
Here, the start() method is overridden in the Car class to provide specialized behavior.

Method Overloading (Conceptual in Python)

Unlike some other languages (like Java or C++), Python does not support method overloading directly — you can't define multiple methods with the same name but different parameters. However, you can achieve similar functionality using default arguments or variable-length arguments.

Example:

class Calculator:
    def add(self, a=None, b=None, c=None):
        if a is not None and b is not None and c is not None:
            return a + b + c
        elif a is not None and b is not None:
            return a + b
        else:
            return a

calc = Calculator()
print(calc.add(2, 3))
print(calc.add(2, 3, 5))
Output:

5
10
Here, a single method add() behaves differently depending on how many arguments are passed — mimicking method overloading.

Operator Overloading

Operator overloading is another form of polymorphism where operators like +, -, and * behave differently based on operand types. Python achieves this through special methods like add(), sub(), etc.

Example:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

p1 = Point(2, 3)
p2 = Point(4, 5)
result = p1 + p2
print(result.x, result.y)
Output:

6 8
Here, the + operator is “overloaded” to add two Point objects by defining the add() method.

Summary

Polymorphism makes Python code flexible, extensible, and elegant. Whether through method overriding, duck typing, or operator overloading, it allows one interface to serve multiple data types and classes.

Concept Description
Polymorphism Ability of different classes to be treated as the same type through a common interface
Duck Typing Behavior-based typing — if an object has required methods, its actual class doesn’t matter
Method Overriding Redefining a method in a derived class
Method Overloading Same method name, different arguments (simulated via default parameters or *args)
Operator Overloading Using special methods like __add__() to redefine operators
This helps in writing cleaner, more maintainable, and reusable code — a hallmark of good object-oriented design. In the next article, we’ll explore Abstraction in Python — how to hide complex implementation details and expose only essential features.
Share this Article