Polymorphism is a very important concept in programming.
Polymorphism enables using a single interface with input of different datatypes, different class or may be for different number of inputs
Let's take an example:
len() function being used for different types 'String' and Data Structures 'Tuple'
print(len("IBMMainframer")) #Output: 13 myTuple = (1, 1, 2,3,45) print(len(myTuple)) #Output: 5 |
add() function being used for two different types of parameters 'add(2,3)' & 'add(2,3,4)'
def add(a, b, c = 0): return a + b + c print(add(2, 3)) #Output: 5 print(add(2, 3, 4)) #Output: 9 |
In python, polymorphism is a way of making a function accept objects of different classes if they behave similarly.
Method overriding is a type of polymorphism in which a child class which is extending the parent class can provide different definition to any function defined in the parent class as per its own requirements.
Method overriding or function overloading is a type of polymorphism in which we can define a number of methods with the same name but with a different number of parameters as well as parameters can be of different types. These methods can perform a similar or different function.
Python doesn't support method overloading on the basis of different number of parameters in functions.
+ operator is used to perform arithmetic addition and string concatenation
num1 = 10 num2 = 20 print(num1+num2) #Output: 30 str1 = "Hello" str2 = " World!" print(str1+str2) #Output: Hello World! |
Imagine a situation in which we have a different class for shapes like Square, Triangle etc which serves as a resource to calculate the area of that shape. Each shape has a different number of dimensions which are used to calculate the area of the respective shape.
Now one approach is to define different functions with different names to calculate the area of the given shapes. The program depicting this approach is shown below:
class Square: def __init__(self, side): self.side = side def calculate_area_sq(self): return self.side * self.side class Triangle: def __init__(self, base, height): self.base = base self.height = height def calculate_area_tri(self): return 0.5 * self.base * self.height sq = Square(5) tri = Triangle(5,4) print("Area of square: ", sq.calculate_area_sq()) print("Area of triangle: ", tri.calculate_area_tri()) |
Area of square: 25 Area of triangle: 10.0 |
The problem with this approach is that the developer has to remember the name of each function separately. In a much larger program, it is very difficult to memorize the name of the functions for every small operation. Here comes the role of method overloading.
Now let's change the name of functions to calculate the area and give them both same name calculate_area() while keeping the function separately in both the classes with different definitions. In this case the type of object will help in resolving the call to the function. The program below shows the implementation of this type of polymorphism with class methods:
class Square: def __init__(self, side): self.side = side def calculate_area(self): return self.side * self.side class Triangle: def __init__(self, base, height): self.base = base self.height = height def calculate_area(self): return 0.5 * self.base * self.height sq = Square(5) tri = Triangle(5,4) print("Area of square: ", sq.calculate_area()) print("Area of triangle: ",tri.calculate_area()) |
Area of square: 25 Area of triangle: 10.0 |
As you can see in the implementation of both the classes i.e. Square as well as Triangle has the function with same name calculate_area(), but due to different objects its call get resolved correctly, that is when the function is called using the object sq then the function of class Square is called and when it is called using the object tri then the function of class Triangle is called.
What we saw in the example above is again obvious behaviour. Let's use a loop which iterates over a tuple of objects of various shapes and call the area function to calculate area for each shape object.
class Square: def __init__(self, side): self.side = side def calculate_area(self): return self.side * self.side class Triangle: def __init__(self, base, height): self.base = base self.height = height def calculate_area(self): return 0.5 * self.base * self.height sq_obj1 = Square(5) tri_obj1 = Triangle(5,4) for obj in (sq_obj1, tri_obj1): print(obj.calculate_area()) |
25 10.0 |
Now this is a better example of polymorphism because now we are treating objects of different classes as an object on which same function gets called.
Here python doesn't care about the type of object which is calling the function hence making the class method polymorphic in nature. This is polymorphism.
Polymorphism in python defines methods in the child class that have the same name as the methods in the parent class. In inheritance, the child class inherits the methods from the parent class. Also, it is possible to modify a method in a child class that it has inherited from the parent class. For example,
class parent: def __init__(self, a, b): self.a = a self.b = b def sum(self): print(f"Sum of a & b : {self.a + self.b}") class child(parent): def __init__(self, a, b): self.a = a self.b = b def sum(self): print(f"Avg of a & b : { (self.a + self.b) / 2}") parent_obj1 = parent(10, 20) parent_obj1.sum() #Output: Sum of a & b : 30 child_obj1 = child(10, 20) child_obj1.sum() #Output: Avg of a & b : 15.0 |
If you have any doubts or queries related to this chapter, get them clarified from our Python Team experts on ibmmainframer Community!