Polymorphism is one of the key principles of object-oriented programming (OOP) in Python. Polymorphism in Python means “many forms”. It refers to the ability to present the same interface for different underlying data types. In simpler terms, polymorphism allows objects of different types to be accessed through the same interface, emphasizing the ability of different objects to respond to the same method calls in a way that is appropriate for their specific types.
Polymorphism
Polymorphism means the same function name (but different signatures) being used for different types. It allows to use the same function or method (can be different signature) for different types of objects, and each object can behave differently based on its type.
In other words, Polymorphism allows functions or methods to process objects differently depending on their data type or class. This can be useful in scenarios where different types of objects share the same method name, but the method may behave differently based on the object calling it.
For example, the +
operator can perform arithmetic addition for numbers and concatenation for strings.
# Polymorphism with + operator
# + operator performs integer addition
print(15 + 30) # Output => 45
# + operator performs string concatenation
print("Courses" + "@shbytes.com") # Output => "Courses@shbytes.com"
Types of Polymorphism in Python
Python supports two main types of polymorphism:
- Compile-time polymorphism – This is also understood as Method Overloading. Python does not natively support this, but we can achieve this using default arguments.
- Run-time polymorphism – This is also understood as Method Overriding. This allows methods in child classes to override methods in parent classes.
Polymorphism with Functions
In Python, we can define functions that can take arguments of any datatype. The same function can operate on different types of objects.
# Function demonstrating polymorphism
def add_objects(obj_1, obj_2):
return obj_1 + obj_2
# Using the same function for integers additions
print(add_objects(40, 70)) # Output => 110
# Using the same function for strings concatenation
print(add_objects("Python", "@shbytes.com")) # Output => Python@shbytes.com
# Using the same function for list extend
print(add_objects([4, 18, 20], [80, 30, 60])) # Output => [4, 18, 20, 80, 30, 60]
# Using the same function for tuple
print(add_objects((4, 18, 20), (80, 30, 60))) # Output => (4, 18, 20, 80, 30, 60)
In this example, The same add_objects(obj_1, obj_2)
function is used for integers addition, strings concatenation, extend of list and tuple. Python’s dynamic typing allows this flexibility.
Polymorphism with Classes
We can create classes that use the same method names for different behaviors.
# PythonCourse Class
class PythonCourse(): # Inherits from Shbytes
def course_details(self):
print("Course: Python Programming\nDuration: 8 Weeks")
# PowerBICourse Class
class PowerBICourse(): # Inherits from Shbytes
def course_details(self):
print("Course: Power BI for Data Analysis\nDuration: 6 Weeks")
def get_course_details(course):
print(course.course_details())
# Creating objects of different classes
python_course = PythonCourse()
powerbi_course = PowerBICourse()
# Calling the same function with different objects
get_course_details(python_course) # Output => Course: Python Programming\nDuration: 8 Weeks
get_course_details(powerbi_course) # Output => Course: Power BI for Data Analysis\nDuration: 6 Weeks
- In this example, we have defined two classes
PythonCourse
andPowerBICourse
. Both class implement their own functioncourse_details()
and give different output. get_course_details()
function calls thecourse_details()
method on different types of class objects (PythonCourse
andPowerBICourse
), and each object responds appropriately based on its own implementation.get_course_details(python_course)
gives an output from thePythonCourse
class. Output =>Course: Python Programming\nDuration: 8 Weeks
get_course_details(powerbi_course)
gives an output from thePowerBICourse
class. Output =>Course: Power BI for Data Analysis\nDuration: 6 Weeks
Polymorphism with Inheritance
Polymorphism is frequently used in inheritance, where a parent class defines a method, and child classes override or extend that method.
# Parent class
class Course:
def course_details(self):
raise NotImplementedError("Subclasses must implement this method")
# Child class 1
class PythonCourse(Course): # Inherits from Course
def course_details(self): # override definition of course_details function from Course class
print("Course: Python Programming\nDuration: 8 Weeks")
# Child class 2
class PowerBICourse(Course): # Inherits from Course
def course_details(self): # override definition of course_details function from Course class
print("Course: Power BI for Data Analysis\nDuration: 6 Weeks")
# create list of objects from Child classes
courses_object_list = [PythonCourse(), PowerBICourse()]
for course_obj in courses_object_list:
course_obj.course_details() # call course_details() function on each object
- In this example,
Course
class defines the functioncourse_details()
, but does not implement it and raiseNotImplementedError
from this fnction. - The
PythonCourse
andPowerBICourse
classes both inherits theCourse
class and implement thecourse_details
method, providing their own implementation. courses_object_list = [PythonCourse(), PowerBICourse()]
– We created a list of objects from both classes.- In the object list loop, we call
course_obj.course_details()
which will call thecourse_details
method from their respective classes.
Program Output
# Output from course_obj.course_details() for PythonCourse class object
Course: Python Programming
Duration: 8 Weeks
# Output from course_obj.course_details() for PowerBICourse class object
Course: Power BI for Data Analysis
Duration: 6 Weeks
Polymorphism in Python – Real-world Example for File Operations
Consider a scenario where we have multiple file formats (e.g., text files, CSV files) and we want to read them using the same interface.
class FileReader:
def read_file(self):
raise NotImplementedError("Subclasses must implement this method")
class TextFileReader(FileReader):
def read_file(self):
return "Reading text file"
class CSVFileReader(FileReader):
def read_file(self):
return "Reading CSV file"
def file_processor(reader):
print(reader.read_file())
# Creating objects of different file readers
text_reader = TextFileReader()
csv_reader = CSVFileReader()
# Processing files using polymorphism
file_processor(text_reader) # Output => Reading text file
file_processor(csv_reader) # Output => Reading CSV file
- In this example,
file_processor
can handle bothTextFileReader
andCSVFileReader
objects in the same way, using polymorphism to adapt to the correct behavior. - This is using the combination of function and inheritance polymorphism.
Summary
In this article, we learned about Polymorphism in Python (with Examples). Polymorphism is a powerful concept that enhances flexibility and re-usability in Python. It allows the same function to handle different types of objects and behaviors seamlessly. Whether we are dealing with objects, functions, or class inheritance, polymorphism simplifies code structure and encourages maintainable and scalable designs.
Code – Github Repository
All code snippets and programs for this article and for Python tutorial, can be accessed from Github repository – Comments and Docstring in Python.