Polymorphism in Python
Polymorphism is one of the pillars of OOP. Polymorphism is derived from the Greek words poly (many) and morphism (forms). This means that a single function or method name can have multiple variations. As part of polymorphism, a Python child class has methods with the same name as a parent class method. This is an essential component of programming. A single type of entity is used to represent a variety of types in various contexts (methods, operators, objects, etc.).
Types of Polymorphism
- Compile-time Polymorphism (Static Binding)
Compile-time polymorphism is determined at compile time and is also known as static binding. In Python, there are two types of compile-time polymorphism:
- Function Overloading
When multiple functions have the same name but differ in the number or type of parameters, this is referred to as function overloading. Python does not support traditional function overloading (as some other languages do), but it can be accomplished by using default argument values and variable-length argument lists.
Examples:
# Adding Numbers
- class Calculator:
def add(self, a, b):
return a + b
def add(self, a, b, c):
return a + b + c
calculator = Calculator()
print(calculator.add(2, 3)) # Output: TypeError
print(calculator.add(2, 3, 4)) # Output: 9
- def add(a, b):
return a + b
result1 = add(2, 3)
print(result1) #
#Output: 5
result2 = add(2.5, 3.5)
print(result2) #
#Output: 6.0
result3 = add(“Hello “, “World”)
print(result3) #
#Output: Hello World
In this example, the add function can accept integers, floats, or strings as arguments. The function’s behavior changes based on the types of a and b.
#Calculating Area
- def calculate_area(base, height=None):
if height is None:
return base**2 # Area of a square
else:
return 0.5 * base * height # Area of a triangle
result1 = calculate_area(4)
print(result1) # Output: 16
result2 = calculate_area(3, 5)
print(result2) # Output: 7.5
- Operator Overloading
Operator overloading allows operators to behave differently based on the operands they work with. In Python, this is achieved by defining special methods (e.g., __add__ for addition, __sub__ for subtraction) within a class.
Examples:
# Adding vectors
- class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
v1 = Vector(2, 3)
v2 = Vector(1, 1)
result = v1 + v2
print(f”Resultant Vector: ({result.x}, {result.y})”)
# Output: Resultant Vector: (3, 4)
We define a vector class in this example. By implementing the __add__ special method, we specify how the + operator should behave when applied to two vector objects. When v1 + v2 is executed, it calls the __add__ method, which creates a new vector object with the sum of the respective components.
# Comparing length
- class Line:
def __init__(self, length):
self.length = length
def __lt__(self, other):
return self.length < other.length
def __gt__(self, other):
return self.length > other.length
line1 = Line(5)
line2 = Line(3)
print(line1 < line2) # Output: False
print(line1 > line2) # Output: True
In this example, we define a line class. By implementing the __lt__ and __gt__ special methods, we define how the < and > operators should behave when comparing two line objects based on their lengths.
Note: These examples demonstrate how you can define custom behavior for operators in Python classes, enabling you to work with user-defined data types naturally and intuitively. Operator overloading enhances the flexibility and readability of your code, making it easier to work with custom objects.
- Run-time Polymorphism (Dynamic Binding)
Run-time polymorphism, also known as dynamic binding, occurs at run time. It allows a subclass to provide a specific implementation of a method defined in its superclass. This is achieved through method overriding.
- Method Overriding
Method overriding is the process of creating a method in a subclass with the same name and signature as a method in its superclass. This allows the subclass to provide a specific implementation of the method, effectively replacing the behavior inherited from the superclass.
Examples:
# Animal Sounds
- class Animal:
def sound(self):
print(“Generic Animal Sound”)
class Dog(Animal):
def sound(self):
print(“Bark”)
class Cat(Animal):
def sound(self):
print(“Meow”)
animal = Animal()
dog = Dog()
cat = Cat()
animal.sound() # Output: Generic Animal Sound
dog.sound() # Output: Bark
cat.sound() # Output: Meow
In this example, we have a base class Animal with a sound method that prints a generic animal sound. We then create two subclasses Dog and Cat which inherit from Animal. Each subclass overrides the sound method with its specific implementation. When we call sound on instances of these classes, the overridden method is executed.
# Display information
- class Person:
def display_info(self):
print(“I am a person.”)
class Student(Person):
def display_info(self):
print(“I am a student.”)
class Teacher(Person):
def display_info(self):
print(“I am a teacher.”)
person = Person()
student = Student()
teacher = Teacher()
person.display_info() # Output: I am a person.
student.display_info() # Output: I am a student.
teacher.display_info() # Output: I am a teacher.
In this example, we have a base class Person with a display_info method that prints “I am a person.”. We then create two subclasses Student and Teacher which inherit from Person. Each subclass overrides the display_info method with its specific information.
Note: These examples demonstrate how method overriding allows subclasses to customize the behavior inherited from their superclass. This is a powerful feature that allows you to create more specialized classes while maintaining a clear and consistent interface.
Benefits of Polymorphism
- Code Reusability
- Flexibility
- Simplifies Code
Conclusion
Polymorphism is a powerful Python concept that improves code flexibility and maintainability. You can write more versatile and reusable code by understanding and implementing various types of polymorphism. To fully utilize Python’s capabilities, incorporate these principles into your OOP practices.
Remember that mastering polymorphism requires practice and experimentation.