Object-Oriented ProgrammingIntermediate8 min43 / 63

Polymorphism

Learn how the same code can work with many different types of objects — and why that makes your programs flexible and powerful.

Imagine you have a TV remote. You press the volume-up button and the volume goes up — whether you own a Sony, Samsung, or LG TV. The button is the same. The behavior underneath is different for each brand.

That idea is polymorphism (poly = many, morph = form). In Python, you can call the same method name on different objects, and each object responds in its own way. Your code stays clean and simple while handling many different types.

See it in action

Visual walkthrough1 / 5
1

One Name, Many Behaviors

Polymorphism means different objects can share the same method name, but each responds in its own way. Think of a TV remote — same volume button, different brand, different circuitry underneath.

poly = many, morph = form — many forms from one interface

#A Simple Example: Animals That Speak

Let's create a few animal classes. Each one has a speak() method, but each animal makes a different sound.

Three classes, same method name, three different results.
class Dog:
    def speak(self):
        return "Woof!"

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

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

dog = Dog()
cat = Cat()
duck = Duck()

print(dog.speak())
print(cat.speak())
print(duck.speak())

Notice that all three classes define a speak() method. Python doesn't care which class an object comes from — it just looks for a method called speak and calls it. This is polymorphism in action.

#Calling Them Uniformly in a Loop

The real power shows up when you put different objects in a list and treat them all the same way.

One loop, four objects of different types — same call, different behavior.
animals = [Dog(), Cat(), Duck(), Dog()]

for animal in animals:
    print(animal.speak())
Think of it like

The Universal Remote Analogy

Think of the for loop as a universal remote. It sends the same signal (speak()) to every device in the list. Each device — Dog, Cat, Duck — interprets that signal in its own way. You write the loop once, and it works for every animal, even ones you add later.

#Duck Typing: If It Quacks Like a Duck...

Python uses a philosophy called duck typing: if an object has the method you need, Python will use it — no questions asked about what type it is.

The saying goes: "If it walks like a duck and quacks like a duck, it's a duck." Python doesn't check IDs. It just checks behavior.

Robot is not an animal, but it has speak() — so the loop works just fine.
class Robot:
    def speak(self):
        return "Beep boop!"

# Robot has nothing to do with animals, but it has speak()
animals = [Dog(), Cat(), Robot()]

for creature in animals:
    print(creature.speak())
Tip

You Don't Need a Shared Parent Class

Duck typing means your classes don't have to inherit from the same base class to work together polymorphically. They just need to share the same method name and signature. This is one of Python's great strengths — it keeps things flexible and simple.

#Polymorphism You Already Know: len() and +

You've already been using polymorphism without realizing it! Python's built-in functions like len() and the + operator work on many different types.

len() and + behave differently depending on the type — that's polymorphism.
print(len("hello"))       # works on a string
print(len([1, 2, 3]))     # works on a list
print(len({"a": 1}))     # works on a dictionary

print("cat" + "fish")     # + joins strings
print([1, 2] + [3, 4])   # + joins lists
print(10 + 5)             # + adds numbers

Python calls the appropriate underlying method for each type. When you write len("hello"), Python calls the string's internal length method. When you write len([1, 2, 3]), it calls the list's internal length method. Same interface, different behavior.

#Method Overriding

Another form of polymorphism is method overriding — when a child class replaces a method it inherited from a parent class.

Dog and Cat override speak(). Fish inherits the default from Animal.
class Animal:
    def speak(self):
        return "..."

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

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

class Fish(Animal):
    pass  # Fish doesn't override speak()

animals = [Dog(), Cat(), Fish()]

for animal in animals:
    print(animal.speak())

The parent class Animal provides a default speak() that returns "...". Dog and Cat override it with their own version. Fish doesn't bother, so it falls back to the parent's version. All three still respond to speak() — that's polymorphism through method overriding.

Common mistake

Forgetting the Method Name Must Match Exactly

Polymorphism only works if the method names match exactly. If you write speak() in one class and Speak() or make_sound() in another, Python won't treat them as interchangeable — it will raise an AttributeError when it can't find the method.

Always double-check your spelling and capitalization when designing a shared interface.

#A Practical Shape Example

Circle and Rectangle each compute area differently, but the loop calls area() the same way on both.
import math

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

    def area(self):
        return math.pi * self.radius ** 2

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

shapes = [Circle(5), Rectangle(4, 6), Circle(3)]

for shape in shapes:
    print(f"Area: {shape.area():.2f}")
Quick check

Which statement best describes polymorphism in Python?

Key takeaways

  • Polymorphism lets you call the same method name on different objects and get behavior appropriate to each.
  • Duck typing means Python only cares whether an object *has* the method — not what type or class it belongs to.
  • You can loop over a mixed list of objects and call the same method on all of them — a huge code simplification.
  • Method overriding is polymorphism: child classes replace parent methods with their own version.
  • Built-ins like `len()` and `+` are everyday examples of polymorphism you already use.
Practice challenges
Test yourself · earn XP
0/4
Predict the output#1

What does this code print?

predict-output
class Dog:
    def speak(self):
        return "Woof!"

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

animals = [Dog(), Cat(), Dog()]

for animal in animals:
    print(animal.speak())
Fix the bug#2

This code is supposed to print the sound each animal makes, but it raises an error. What is wrong?

fix-bug
class Dog:
    def speak(self):
        return "Woof!"

class Cat:
    def Make_Sound(self):
        return "Meow!"

animals = [Dog(), Cat()]

for animal in animals:
    print(animal.speak())
Fill in the blank#3

Complete the Animal base class so that Dog inherits from it and the output is Woof!

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

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

print(Dog().speak())
Reorder the lines#4

Put these lines in the right order so the code prints the area of each shape.

1
        return 3.14 * self.radius ** 2
2
shapes = [Circle()]
3
for shape in shapes:
4
    def area(self):
5
class Circle:
6
    print(shape.area())
Your turn
Practice exercise

Create three classes: Trumpet, Guitar, and Piano. Each should have a play() method that returns a short description of the sound that instrument makes (e.g., "Trumpet goes: Toot toot!"). Then create a list containing one of each instrument and loop through it, printing the result of play() for each.

Try it live — edit the code and hit Run to execute real Python:

solution.py · editable