Python tutorials > Object-Oriented Programming (OOP) > Polymorphism > What is polymorphism?
What is polymorphism?
Understanding Polymorphism
Duck Typing
Duck Typing - Example
do_something
function accepts any object that has quack
and fly
methods. It doesn't care if the object is a Duck
or a Person
; it only cares that the object can perform those actions. This illustrates duck typing, where the object's behavior determines its suitability.
class Duck:
def quack(self):
print("Quack, quack!")
def fly(self):
print("Duck is flying")
class Person:
def quack(self):
print("Person imitating a duck")
def fly(self):
print("Person waving arms, trying to fly!")
def do_something(animal):
animal.quack()
animal.fly()
duck = Duck()
person = Person()
do_something(duck)
do_something(person)
Inheritance and Polymorphism
Inheritance Polymorphism - Example
Animal
is the base class, and Dog
and Cat
are derived classes. Each derived class overrides the speak
method to provide its own specific implementation. The animal_sound
function can accept any object that is an instance of Animal
or any of its subclasses, and it will call the appropriate speak
method based on the object's actual type.
class Animal:
def speak(self):
print("Generic animal sound")
class Dog(Animal):
def speak(self):
print("Woof!")
class Cat(Animal):
def speak(self):
print("Meow!")
def animal_sound(animal):
animal.speak()
animal = Animal()
dog = Dog()
cat = Cat()
animal_sound(animal)
animal_sound(dog)
animal_sound(cat)
Method Overriding
concepts behind the snippet
Inheritance: When combined with inheritance, polymorphism enables subclasses to provide specialized implementations of inherited methods.
Dynamic Binding: In Python, method calls are resolved at runtime, which means the specific method to be executed is determined by the object's actual type, not its declared type. This is known as dynamic binding or late binding and is essential for polymorphism to work.
Real-Life Use Case Section
Shape
with subclasses like Circle
, Rectangle
, and Triangle
. Each shape class would have its own draw()
method. The application can then store a collection of Shape
objects and iterate through them, calling the draw()
method on each object. Polymorphism ensures that the correct draw()
method is called for each specific shape, even though the application only knows it's dealing with Shape
objects. This allows for easy addition of new shape types without modifying the core drawing logic.
Best Practices
Favor Composition over Inheritance: In some cases, composition (creating objects that contain other objects) can be a more flexible alternative to inheritance. Composition allows you to achieve polymorphism without the tight coupling that inheritance can create.
Design for Extensibility: When designing your classes, consider how they might be extended in the future. Use polymorphism to create flexible and adaptable code that can accommodate new requirements.
Interview Tip
When to use them
Memory footprint
Alternatives
if/elif/else
) to handle different object types explicitly. However, this approach can lead to less maintainable and less extensible code.
Function Overloading (Not Directly Supported in Python): In some languages, you can overload functions, providing multiple definitions for the same function name with different parameter types. Python doesn't directly support function overloading based on parameter types, but you can achieve similar results using default argument values or variable-length argument lists (*args
and **kwargs
).
pros
Flexibility: Polymorphism makes your code more flexible and adaptable to change. You can easily add new object types without modifying existing code.
Maintainability: Polymorphic code is easier to maintain and understand because it is more modular and less coupled.
Extensibility: Polymorphism allows you to easily extend your code to support new functionality without breaking existing code.
cons
Potential for Runtime Errors: With Duck Typing, if an object doesn't actually implement the expected methods, you might encounter runtime errors. Using Abstract Base Classes can help mitigate this risk.
Debugging Challenges: Polymorphism can make debugging more challenging because the specific code that is executed depends on the object's runtime type.
FAQ
-
What is the difference between static polymorphism and dynamic polymorphism?
Static polymorphism (also known as compile-time polymorphism) refers to polymorphism that is resolved at compile time. Python doesn't directly support static polymorphism in the same way as languages like C++ (e.g., through function overloading). Dynamic polymorphism (also known as runtime polymorphism) refers to polymorphism that is resolved at runtime. Python primarily uses dynamic polymorphism through duck typing and method overriding. -
How does polymorphism relate to interfaces?
An interface defines a set of methods that a class must implement. Polymorphism allows you to treat objects of different classes that implement the same interface in a uniform way. In Python, interfaces are often implicitly defined through duck typing or explicitly defined using Abstract Base Classes (ABCs). -
Is polymorphism only applicable to object-oriented programming?
While polymorphism is a core concept in object-oriented programming, the underlying principle of using a single interface for multiple data types can be applied in other programming paradigms as well. For example, function overloading (in languages that support it) can be considered a form of polymorphism.