Python Polymorphism
Table of Contents + −
In the last lesson you learned Inheritance. A child class gets all the abilities of a parent class. Now we take the next step. What if many different classes share the same method name? And what if each one should behave its own way? That is what polymorphism gives you.
🤔 Why Polymorphism?
Picture an app that holds a list of animals. A dog, a cat, a cow. You want each one to make its sound. Without polymorphism you end up writing code like this:
if animal_type == "dog": print("Woof!")elif animal_type == "cat": print("Meow!")elif animal_type == "cow": print("Moo!")See the problem? Every time you add a new animal, you go back and add another elif. The code keeps growing. It gets messy fast.
Polymorphism flips this around. Each class knows how to make its own sound. You just say “make your sound” and the right thing happens. No long if chain.
💡 What Polymorphism Means
The word looks scary but the idea is simple. “Poly” means many. “Morph” means form. So polymorphism means one name, many forms.
In Python it means this. The same method name can do different things. It depends on which class the object came from.
Think of a TV remote. The power button is always the “power button”. But press it on your TV and the TV turns on. Press the same kind of button on the AC and the AC turns on. One button name, a different result on each device. That is polymorphism.
🐾 The Same Method on Different Classes
Let’s build the animal example for real. We make three classes. Each one has a method with the exact same name. It is called speak(). But each speak() returns a different sound.
class Dog: def speak(self): return "Woof!"
class Cat: def speak(self): return "Meow!"
class Cow: def speak(self): return "Moo!"Here is what is going on, point by point:
- All three classes have a method called
speak. - The name is the same, but the body is different in each class.
Dog.speak()gives"Woof!",Cat.speak()gives"Meow!",Cow.speak()gives"Moo!".
Now the nice part. We put one of each into a list and loop over them. We call speak() on every object the same way. Each object responds in its own voice.
animals = [Dog(), Cat(), Cow()]
for animal in animals: print(animal.speak())Running that prints:
Output
Woof!Meow!Moo!Look at the loop again. It does not check the type of the animal. It never asks “are you a dog or a cat?”. It just says animal.speak() and trusts each object to do the right thing. That is the whole point.
Tip
Python does not care about the class. It only cares that the object has a speak() method it can call. This relaxed style is called duck typing. If it walks like a duck and quacks like a duck, Python treats it like a duck.
🔁 Method Overriding
Polymorphism often shows up together with inheritance. A child class can have a method with the same name as its parent. When that happens, the child’s version replaces the parent’s. We call this method overriding.
Let’s see it. We start with a parent class Animal that has a basic speak(). Then each child class overrides it with its own sound.
class Animal: def speak(self): return "Some generic animal sound"
class Dog(Animal): def speak(self): return "Woof!"
class Cat(Animal): def speak(self): return "Meow!"Here is what each piece does:
Animalis the parent. Itsspeak()returns a plain default sound.Doginherits fromAnimalbut writes its ownspeak(). The child version wins.Catdoes the same with its own sound.
Now let’s call speak() on one object from each class. We include a plain Animal too.
animals = [Animal(), Dog(), Cat()]
for animal in animals: print(animal.speak())This prints:
Output
Some generic animal soundWoof!Meow!The Animal object falls back to the parent’s speak(), because it has no override. The Dog and Cat objects use their own overridden speak(). Same method name, a different result each time. Polymorphism and overriding working together.
Caution
Always run your code and read the real output. Do not assume what it prints.
🤝 Reusing the Parent with super()
Sometimes you do not want to throw away the parent’s method. You want to add to it. You can call the parent’s version inside the child using super(). Then you add your own bit.
This Cat keeps the parent’s message and adds its own sound after it.
class Animal: def speak(self): return "I am an animal."
class Cat(Animal): def speak(self): parent_words = super().speak() return f"{parent_words} I say Meow!"
print(Cat().speak())That prints:
Output
I am an animal. I say Meow!So super().speak() runs the parent’s method and hands back its result. Then the child glues its own words on the end. You override, but you still reuse what the parent already said.
📋 One Method Name, Many Behaviours
Here is the same idea in a small table, so you can see it at a glance.
| Object | Method called | Result |
|---|---|---|
| Dog | speak() | Woof! |
| Cat | speak() | Meow! |
| Cow | speak() | Moo! |
Same call, three different results. The caller does not need to know or care which class it is talking to.
⚠️ Common Mistakes
A few things trip people up when they first use polymorphism:
- Spelling the method name differently in each class. If
Doghasspeak()butCathassay(), the loop breaks. The names must match exactly.
# ❌ Avoid: different method names break the shared loopclass Dog: def speak(self): return "Woof!"
class Cat: def say(self): # wrong name, the loop calling speak() will crash on this return "Meow!"
# ✅ Good: every class uses the same method nameclass Dog: def speak(self): return "Woof!"
class Cat: def speak(self): return "Meow!"- Going back to type checks. If you find yourself writing
if isinstance(animal, Dog)inside the loop, you have thrown polymorphism away. Let each class handle its own behaviour. - Forgetting
self. Every method needsselfas its first parameter. If you forget it, Python will complain when you call the method.
✅ Best Practices
Keep these habits and polymorphism stays clean and easy:
- Give the shared action one clear name and use it everywhere (
speak,area,draw,save). - Let the loop call that one method and trust the objects. Do not test their types.
- Use
super()when the child should extend the parent, not fully replace it. - Run the code and read the real output before you believe what it prints.
🧩 What You’ve Learned
A quick recap of the ideas from this lesson:
- ✅ Polymorphism means one method name can behave differently on different classes.
- ✅ You can put mixed objects in a list and call the same method on each, and each responds its own way.
- ✅ Method overriding is when a child class replaces a parent method with its own version.
- ✅
super()lets a child reuse the parent’s method and add to it instead of replacing it. - ✅ Python uses duck typing. It cares that the method exists, not which class the object is.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does polymorphism let you do?
Why: Polymorphism means one method name, many forms, behaving differently per class.
- 2
In the loop `for animal in animals: print(animal.speak())`, how does Python know which sound to make?
Why: The call is the same, but each object runs its own version of speak().
- 3
What is method overriding?
Why: Overriding is when the child writes its own version of a method the parent already had.
- 4
What does super().speak() do inside a child class?
Why: super() calls the parent's version so the child can reuse and extend it.
🚀 What’s Next?
You now know how one method name can wear many faces. Next we look at how to protect the data inside a class so it cannot be changed by accident.