</>
Skip to content
Python lessons (27/45)

Python — Polymorphism

One call, many behaviors

Poly-morphism = "many shapes." Different objects respond to the same call in their own way:

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

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

class Robot:
    def speak(self): return "BEEP"

for thing in [Dog(), Cat(), Robot()]:
    print(thing.speak())     # each type answers its own way

Python never asked what class they are — only "do you have .speak()?"

Duck typing — Python's philosophy

"If it walks like a duck and quacks like a duck, it's a duck."

No inheritance required. Any object with the right methods works:

def total_length(things):
    return sum(len(t) for t in things)   # anything with len()

total_length(["ab", "cd"])     # lists ✓
total_length("hello")          # strings ✓

Contrast with Java-style polymorphism, which demands a shared parent class. Python's version is informal and flexible.

Overriding + super() (the OOP flavor)

With real inheritance:

class Shape:
    def area(self):
        raise NotImplementedError

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

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

shapes = [Circle(1), Square(2)]
print(sum(s.area() for s in shapes))   # 7.14…

The loop doesn't care which subclass each object is.

Built-in polymorphism everywhere you've already been

len("hi"); len([1]); len({"a": 1})      # one name, three implementations
"-" * 5; [0] * 3                         # * behaves per type
print(anything)                          # str() protocol on every object
for x in …                               # works on ANY iterable

Your own classes can join these protocols by defining dunder methods:

class Team:
    def __init__(self, members): self.members = members
    def __len__(self): return len(self.members)
    def __contains__(self, m): return m in self.members

len(Team(["Ada"]))      # 1
"Ada" in Team(["Ada"])  # True

That's how your types become first-class citizens of Python's syntax.

Design tip: check capabilities (hasattr(obj, "speak"), try/except) rather than types (isinstance chains) when you want maximum flexibility — but isinstance remains right when a genuine hierarchy exists.

Mini Practice

  1. Three-payment-method classes, each with pay(amount); loop over all.
  2. len()-supporting Playlist class.
  3. Duck-typed render() working on both dicts and objects.
  4. Shape hierarchy total-area sum.
  5. Prove "3" * 3 vs 3 * 3 — operator polymorphism.

Next: scope →

Related Topics

Frequently Asked Questions about Polymorphism

What is Polymorphism in Python?

Polymorphism is a fundamental concept in Python. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Polymorphism?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Polymorphism.

Why is Polymorphism important in Python?

Polymorphism is essential for Python development. Understanding this concept will help you write better code and solve real-world problems more effectively.