CS Pathfinder Logo CS Pathfinder

Unit 5 · Advanced Topics

Polymorphism

Polymorphism is a core concept of Object-Oriented Programming that allows objects of different classes to be treated through a unified interface, enabling a single function, method, or operator to work with multiple data types.

Table of Contents

University Definition

Polymorphism (from Greek: "many forms") is the ability of a single interface to represent different underlying data types. In Python, polymorphism allows the same function or method name to work with objects of different classes, and the correct version is determined at runtime.

Polymorphism is mainly of two types:

  • Compile-time (Static) Polymorphism — Achieved through method/function overloading. Python does not support traditional overloading.
  • Runtime (Dynamic) Polymorphism — Achieved through method overriding and duck typing. This is the primary form in Python.
Polymorphism
    |
    ├── Method Overriding (Runtime)
    ├── Duck Typing (Runtime)
    ├── Operator Overloading (Compile-time via dunder methods)
    └── Function Overloading (via default arguments)

1. Method Overriding (Runtime Polymorphism)

When a child class redefines a method from its parent, the correct method is called based on the object's actual type at runtime. This is the most common form of polymorphism in Python.

class Animal:
    def sound(self):
        return "Some generic sound"

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

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

class Bird(Animal):
    def sound(self):
        return "Chirp"

# Polymorphism in action — same function, different behavior
animals = [Dog(), Cat(), Bird(), Animal()]
for animal in animals:
    print(animal.sound())

# Output: Bark, Meow, Chirp, Some generic sound

2. Duck Typing

University Definition

Duck Typing is a concept where the type or class of an object is less important than the methods and properties it defines. If an object has the required methods, it can be used — regardless of its actual class. The name comes from the phrase: "If it walks like a duck and quacks like a duck, it must be a duck."

class Car:
    def start(self):
        return "Car engine started"

class Bike:
    def start(self):
        return "Bike engine started"

class Boat:
    def start(self):
        return "Boat engine started"

# No common parent — but all have start()
def ignite(vehicle):
    print(vehicle.start())

ignite(Car())   # Car engine started
ignite(Bike())  # Bike engine started
ignite(Boat())  # Boat engine started

University Exam Tip

Duck typing differentiates Python from statically typed languages like Java/C++. In exams, emphasize that Python does not check types — it checks whether the object has the required method. This makes Python more flexible.

3. Operator Overloading

Python allows you to redefine the behavior of built-in operators for custom objects using dunder (double underscore) methods. This is a form of compile-time polymorphism.

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

    # Operator + overloading
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

    # len() overloading
    def __len__(self):
        return int((self.x**2 + self.y**2)**0.5)

    # str() overloading
    def __str__(self):
        return f"({self.x}, {self.y})"

p1 = Point(3, 4)
p2 = Point(1, 2)

print(p1 + p2)    # (4, 6)
print(len(p1))    # 5
print(str(p1))    # (3, 4)

len() — Polymorphic Function

The len() function works with strings, lists, tuples, dicts, and custom classes — each returning the appropriate length. This is built-in polymorphism.

print(len("Hello"))          # 5 (string)
print(len([1, 2, 3]))        # 3 (list)
print(len({"a": 1, "b": 2}))  # 2 (dict)
print(len((10, 20)))         # 2 (tuple)

Common Dunder Methods for Operator Overloading

Operator / Function Dunder Method Purpose
+ (add)__add__Addition of objects
- (sub)__sub__Subtraction of objects
* (mul)__mul__Multiplication of objects
len()__len__Length of object
str()__str__String representation
repr()__repr__Developer string repr
== (eq)__eq__Equality comparison
< (lt)__lt__Less-than comparison

4. Function Overloading (Using Default Arguments)

Python does not support traditional function overloading (same function name with different parameter types). Instead, we simulate it using default arguments or *args/**kwargs.

def add(a, b=0, c=0):
    return a + b + c

print(add(5))           # 5
print(add(5, 3))        # 8
print(add(5, 3, 2))     # 10

# Using *args for variable arguments
def multiply(*args):
    result = 1
    for num in args:
        result *= num
    return result

print(multiply(2, 3))       # 6
print(multiply(2, 3, 4))    # 24

Practical Example: Polymorphism with Shapes

class Circle:
    def __init__(self, radius):
        self.radius = radius

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

    def __str__(self):
        return f"Circle(r={self.radius})"

class Rectangle:
    def __init__(self, l, w):
        self.l = l
        self.w = w

    def area(self):
        return self.l * self.w

    def __str__(self):
        return f"Rectangle({self.l}x{self.w})"

class Triangle:
    def __init__(self, base, height):
        self.base = base
        self.height = height

    def area(self):
        return 0.5 * self.base * self.height

    def __str__(self):
        return f"Triangle(b={self.base},h={self.height})"

# Polymorphism: same function, different objects
shapes = [Circle(5), Rectangle(4, 6), Triangle(3, 8)]

for shape in shapes:
    print(f"{shape} → Area = {shape.area()}")

# Output:
# Circle(r=5) → Area = 78.5
# Rectangle(4x6) → Area = 24
# Triangle(b=3,h=8) → Area = 12.0

Common Mistakes

  • Trying to overload a function by defining it twice — Python uses the last definition only.
  • Confusing polymorphism with overloading — polymorphism is about one interface, many forms.
  • Forgetting self parameter when overriding methods.
  • Assuming Python checks object types — it does not (duck typing).

Key Points

Polymorphism means "many forms" — one interface, multiple implementations.

Method overriding is the primary form of runtime polymorphism in Python.

Duck typing allows objects of unrelated classes to be used interchangeably.

Operator overloading uses dunder methods like __add__, __len__, __str__.

Python does not support traditional function overloading — use default args or *args.

Built-in functions like len(), str(), print() are themselves polymorphic.

Practice Questions

  1. Write a program using method overriding where a parent class Vehicle has a start() method and child classes override it.
  2. Explain duck typing with a code example involving two unrelated classes.
  3. Overload the + operator in a class Matrix to add two 2×2 matrices.
  4. Difference between polymorphism and inheritance.
  5. How does len() demonstrate polymorphism? Give 3 examples.

Summary

Polymorphism is a powerful OOP feature that makes code flexible and extensible. Python achieves it through method overriding, duck typing, and operator overloading. Understanding polymorphism is essential for writing clean, reusable code and for answering university exam questions on OOP.

Python Programming Handwritten Notes

Master Python Programming with Easy Handwritten Notes – Perfect for Interviews, Placements, GATE & Exams.