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
— step through the idea, then dive into the details below.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.
#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.
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.
animals = [Dog(), Cat(), Duck(), Dog()]
for animal in animals:
print(animal.speak())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.
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())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.
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 numbersPython 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.
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.
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
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}")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.
What does this code print?
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())This code is supposed to print the sound each animal makes, but it raises an error. What is wrong?
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())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())
Put these lines in the right order so the code prints the area of each shape.
return 3.14 * self.radius ** 2
shapes = [Circle()]
for shape in shapes:
def area(self):
class Circle:
print(shape.area())
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: