1. Introduction: What Is Polymorphism?
In Object-Oriented Programming (OOP), polymorphism is an advanced core concept that describes how entities can take on multiple forms.
- Etymology: The word is derived from two roots—"Poly", meaning multiple, and "morph", meaning form. Therefore, polymorphism literally translates to "multiple forms".
- Real-world analogy: In the physical world, an object category can take on diverse forms. For instance, consider an Animal. An animal's form can be a Dog, a Cat, a Fish, or a Pigeon. While all of these entities belong to the animal category, their specific behaviors differ significantly.
- OOP definition: Polymorphism allows classes that inherit from other classes—or distinct classes sharing similar interfaces—to define and execute behaviors differently, enabling a single object reference to take different forms and actions.
2. Polymorphism Across Different Classes (Common Interface)
Polymorphism allows you to treat different classes uniformly by calling the same method name across distinct objects.
Code Walkthrough: The Dog and Cat Classes
In this example, both the Dog class and the Cat class define a method named speak(), but each prints a sound specific to that animal:
# 1. Defining the Dog class with a speak method
class Dog:
def speak(self):
print("woof")
# 2. Defining the Cat class with a speak method
class Cat:
def speak(self):
print("meow")
# 3. Storing instances of both classes in a single list
pets = [Dog(), Cat()]
# 4. Iterating through the list and executing speak() polymorphically
for pet in pets:
pet.speak()
Execution and Output:
woof
meow
How It Works
- The list
pets contains two distinct objects: the first belongs to Dog and the second belongs to Cat.
- When the
for loop iterates over pets, it executes pet.speak() on each element.
- Python dynamically calls
Dog.speak() on the first pass (printing "woof") and Cat.speak() on the second pass (printing "meow").
- This demonstrates how different classes can be grouped together and executed through a shared interface.
3. Method Overriding in Polymorphism
Method overriding occurs within an inheritance hierarchy when a child (derived) class rewrites or redefines a method that already exists in its parent (base) class.
Code Walkthrough: The Vehicle and Car Hierarchy
Consider a base class Vehicle with a general move() method, and a subclass Car that inherits from Vehicle and overrides move():
# 1. Base (Parent) Class
class Vehicle:
def move(self):
print("vehicle is moving")
# 2. Derived (Child) Class overriding the move method
class Car(Vehicle):
def move(self):
print("car is driving")
# 3. Instantiating a Car object and invoking move()
car1 = Car()
car1.move()
Execution and Output:
car is driving
How Python Evaluates This
- Even though
Car inherits from Vehicle, calling car1.move() executes the overridden version inside Car.
- The program outputs "car is driving" rather than "vehicle is moving" because the parent class's implementation has been overridden by the child class.
4. Method Overloading in Python (Using Default Arguments)
Method overloading refers to using a single method across multiple scenarios by altering the number of input arguments it accepts.
- The problem: Suppose a program needs an
add method capable of adding one number, two numbers, or three numbers. Creating three distinct functions (add_one_number, add_two_numbers, add_three_numbers) creates redundant code.
- The Python solution: Python achieves method overloading within a single method by assigning default values to input parameters, making those arguments optional.
Code Walkthrough: The Calculator Class
We define an add method where parameter a is compulsory, while parameters b and c are given default values of 0:
class Calculator:
# Defining method with default arguments for overloading
def add(self, a, b=0, c=0):
return a + b + c
# Instantiating the calculator object
calc1 = Calculator()
# Calling add() with a single argument
print("One Argument:", calc1.add(5))
# Calling add() with two arguments
print("Two Arguments:", calc1.add(5, 10))
# Calling add() with three arguments
print("Three Arguments:", calc1.add(5, 10, 15))
Execution and Output:
One Argument: 5
Two Arguments: 15
Three Arguments: 30
Step-by-Step Execution Analysis
- Single argument (
calc1.add(5)): Because b and c are omitted, Python defaults them to 0. The calculation evaluates to 5 + 0 + 0 = 5.
- Two arguments (
calc1.add(5, 10)): The value 10 is bound to b, while c defaults to 0. The calculation evaluates to 5 + 10 + 0 = 15.
- Three arguments (
calc1.add(5, 10, 15)): All three values are supplied, overriding the defaults. The calculation evaluates to 5 + 10 + 15 = 30.
By defining optional parameters, a single method dynamically adapts to different numbers of arguments without rewriting multiple function variants.