Polymorphism
Polymorphism means "many forms." It allows objects of different classes to be treated as the same type, as long as they share a common interface. The same method call can work differently depending on the object type.
Think of it like a remote control - you press the same "power" button, but it does different things for a TV, fan, or light.
To demonstrate polymorphism, consider the following example where we want different animals to make sounds:
❌ Without Polymorphism
# animals.py class Dog: def make_sound(self): print("Woof!") class Cat: def make_sound(self): print("Meow!") class Duck: def make_sound(self): print("Quack!") # main.py dog = Dog() cat = Cat() duck = Duck() # Have to call each one separately dog.make_sound() cat.make_sound() duck.make_sound() # Can't easily handle them together animals = [dog, cat, duck] # Would need to check type for each one# animals.py class Dog: def make_sound(self): print("Woof!") class Cat: def make_sound(self): print("Meow!") class Duck: def make_sound(self): print("Quack!") # main.py dog = Dog() cat = Cat() duck = Duck() # Have to call each one separately dog.make_sound() cat.make_sound() duck.make_sound() # Can't easily handle them together animals = [dog, cat, duck] # Would need to check type for each one
Problem: While each animal has a
make_soundmethod, we can't easily treat them all the same way or add new animals without changing existing code.
✅ With Polymorphism
# animal.py class Animal: def make_sound(self): pass # This will be overridden by child classes# animal.py class Animal: def make_sound(self): pass # This will be overridden by child classes
# dog.py from animal import Animal class Dog(Animal): def make_sound(self): print("Woof!") def fetch(self): print("Dog is fetching the ball!")# dog.py from animal import Animal class Dog(Animal): def make_sound(self): print("Woof!") def fetch(self): print("Dog is fetching the ball!")
# cat.py from animal import Animal class Cat(Animal): def make_sound(self): print("Meow!") def climb(self): print("Cat is climbing the tree!")# cat.py from animal import Animal class Cat(Animal): def make_sound(self): print("Meow!") def climb(self): print("Cat is climbing the tree!")
# duck.py from animal import Animal class Duck(Animal): def make_sound(self): print("Quack!") def swim(self): print("Duck is swimming!")# duck.py from animal import Animal class Duck(Animal): def make_sound(self): print("Quack!") def swim(self): print("Duck is swimming!")
# main.py from dog import Dog from cat import Cat from duck import Duck # Create different animals animals = [ Dog(), Cat(), Duck() ] # Polymorphism in action - same method call, different behaviors def make_all_animals_sound(animals_list): for animal in animals_list: animal.make_sound() # Each animal makes its own sound! make_all_animals_sound(animals) # We can also add new animals without changing existing code class Cow(Animal): def make_sound(self): print("Moo!") animals.append(Cow()) make_all_animals_sound(animals)# main.py from dog import Dog from cat import Cat from duck import Duck # Create different animals animals = [ Dog(), Cat(), Duck() ] # Polymorphism in action - same method call, different behaviors def make_all_animals_sound(animals_list): for animal in animals_list: animal.make_sound() # Each animal makes its own sound! make_all_animals_sound(animals) # We can also add new animals without changing existing code class Cow(Animal): def make_sound(self): print("Moo!") animals.append(Cow()) make_all_animals_sound(animals)
Now:
- All animals can be treated as the same type (
Animal). - The same method call (
make_sound()) produces different results. - New animal types can be added without changing existing code.
This approach makes the code:
- ✅ More flexible - easy to extend
- ✅ More reusable - same code works with different types
- ✅ Easier to maintain - add new types without breaking old code