Advertisement
🏗️ OOP

Python Polymorphism – One Interface, Many Implementations

Polymorphism means "many forms". In Python, polymorphism lets different classes respond to the same method call in their own way. You can call area() on a Circle, a Rectangle, or a Triangle — each calculates it differently but the interface is identical. This is the power of polymorphism.

⏱️ 20 min read🎯 Intermediate📅 Updated 2026

Method Overriding

A subclass can override a parent method to change its behaviour.

Python
class Animal:
    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):        # Override
        return "Woof!"

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

class Duck(Animal):
    def speak(self):
        return "Quack!"

animals = [Dog(), Cat(), Duck()]
for animal in animals:
    print(animal.speak())   # Each responds differently
▶ Output
Woof! Meow! Quack!

Duck Typing

"If it walks like a duck and quacks like a duck, it's a duck." Python doesn't require inheritance — any object with the right method works.

Python
class Dog:
    def speak(self): return "Woof!"

class Robot:
    def speak(self): return "Beep boop!"

class Human:
    def speak(self): return "Hello!"

# No shared base class needed!
entities = [Dog(), Robot(), Human()]
for e in entities:
    print(e.speak())
▶ Output
Woof! Beep boop! Hello!

Polymorphism with Abstract Methods

Use ABC to enforce that subclasses implement required methods.

Python
from abc import ABC, abstractmethod
import math

class Shape(ABC):
    @abstractmethod
    def area(self): ...

    @abstractmethod
    def perimeter(self): ...

class Circle(Shape):
    def __init__(self, r): self.r = r
    def area(self): return math.pi * self.r**2
    def perimeter(self): return 2 * math.pi * self.r

class Square(Shape):
    def __init__(self, s): self.s = s
    def area(self): return self.s**2
    def perimeter(self): return 4 * self.s

for shape in [Circle(5), Square(4)]:
    print(f"Area: {shape.area():.2f}, Perimeter: {shape.perimeter():.2f}")
▶ Output
Area: 78.54, Perimeter: 31.42 Area: 16.00, Perimeter: 16.00
Advertisement

Operator Overloading

Define special methods to make operators work with your classes.

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

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

    def __str__(self):
        return f"Vector({self.x}, {self.y})"

v1 = Vector(1, 2)
v2 = Vector(3, 4)

print(v1 + v2)    # Vector(4, 6)
print(v1 * 3)     # Vector(3, 6)
▶ Output
Vector(4, 6) Vector(3, 6)

Duck Typing: Python's Polymorphism Without Inheritance

In many languages polymorphism requires a shared base class. Python uses duck typing: "if it walks like a duck and quacks like a duck, it's a duck." Any object with the right method works — no common ancestor needed.

class Dog:  quack = None
class Duck:
    def speak(self): return "Quack"
class Cat:
    def speak(self): return "Meow"

for animal in (Duck(), Cat()):
    print(animal.speak())   # works on both — no shared base class

Operator polymorphism via magic methods

The same + means different things by type — that's polymorphism too. Your classes join in by defining __add__, __len__, __str__:

print(3 + 4)        # 7   (integer add)
print("a" + "b")    # ab  (string concat)
print([1] + [2])    # [1, 2] (list extend)

EAFP style: prefer try: obj.speak() over if isinstance(obj, Duck). Checking behavior beats checking type — it keeps your code open to new classes you haven't met yet.

🏋️ Practical Exercise

Model animals with shared behavior:

  1. Create a base class Animal with a speak() method.
  2. Create Dog, Cat, and Cow subclasses that override speak().
  3. Put several animals in a list and call speak() on each in one loop.
  4. Observe how the same call produces different behavior per type.

🔥 Challenge Exercise

Write a function total_area(shapes) that accepts any iterable of objects exposing an area() method (Circle, Square, Triangle, …) and returns their combined area — relying on duck typing rather than a shared base class. Then add a Square class that overloads the + operator to combine two squares into one with the summed area, demonstrating operator-level polymorphism.

📋 Summary

  • Polymorphism lets a single interface work with objects of different types.
  • Method overriding replaces a parent method in a subclass so the same call behaves differently per type.
  • Duck typing means Python cares about whether an object has the needed method, not its class — “if it walks like a duck…”.
  • Python does not support traditional method overloading; use default or variable arguments instead.
  • Operator overloading (via magic methods) is polymorphism at the operator level.
  • Abstract base classes enforce a shared interface that polymorphic code can rely on.

Interview Questions on Polymorphism

  • What is polymorphism in object-oriented programming?
  • What is method overriding and how does it relate to polymorphism?
  • What is duck typing in Python?
  • Does Python support method overloading? Why or why not?
  • How does operator overloading demonstrate polymorphism?
  • What is the difference between overriding and overloading?
  • How does polymorphism work together with abstract base classes?

FAQ

What is the difference between overriding and overloading? +

Overriding redefines an inherited method in a subclass (same name and signature). Overloading defines multiple versions of a method differing by arguments. Python supports overriding natively but not true overloading — default and *args arguments cover those cases.

What is duck typing? +

A style where an object’s suitability is determined by the methods it has, not its type. If an object has an area() method, polymorphic code can use it regardless of which class it belongs to — “if it quacks like a duck, it’s a duck.”

Do I need inheritance for polymorphism in Python? +

No. Thanks to duck typing, unrelated classes that share a method name can be used interchangeably without a common base class. Inheritance and abstract base classes are one way to guarantee that shared interface, not a requirement.

How does operator overloading relate to polymorphism? +

Operators like + behave differently depending on operand type — integers add, strings concatenate, lists extend. By implementing magic methods you extend this polymorphic behavior to your own classes.