Polymorphism in Python with Examples

Posted in /  

Polymorphism in Python with Examples
vinaykhatri

Vinay Khatri
Last updated on April 23, 2024

    Object-Oriented Programming has four basic features, Inheritance, Data Abstraction, Data Encapsulation, and Polymorphism. And out of these features, Polymorphism is the crucial one, and if a Programming language does not support Polymorphism, it does not even consider an Object-Oriented Programming language.

    As an object-oriented programming language, Python supports Polymorphism, and this tutorial will teach you what polymorphism is in Python and how to implement it. By the end of this tutorial, you will have a solid understanding of

    1. What is Polymorphism in Python
    2. Method Overriding
    3. What is function overloading and,
    4. Operator Overloading

    What is Polymorphism in Python? OOPS Concept

    Polymorphism is a Greek word that means “having Multiple Forms”, and in Programming, Polymorphism has the same concept but here it says an object can take many forms. In Python, the Polymorphism concept allows a particular object to perform different tasks in different scenarios.

    The most common example of Polymorphism is the + operator. The + operator performs the addition operation between two number objects, and the same + operator performs string concatenation or joining between two string objects. This behaviour of the + operator, where it can take a different form in different scenarios, is a classical example of Polymorphism.

    Note: Polymorphism does not apply to every Python object.

    Another Real World Example of Polymorphism is you. You can be an Employee in a company, Husband or wife of your spouse and a striker while playing football. This acquiring of different forms at different places is what Polymorphism.

    Let’s Build a solid understanding of Polymorphism with a common Python Example

    Example: Python Polymorphism with len() function

    In Python, you have used the len() function many times, as the name suggests, the len() function is generally used to calculate the total length of an object. But which length to compute depends upon the data type passed as an argument to the len() function.

    For a list object, the len() function counts the total number of items present in the list. For a string, the len() function counts the total number of characters present in the string. For a dictionary object, the len() function counts the number of keys present in the dictionary.

    The len() function name is the same for all the objects list, string, and dictionary, but it performs different operations on different objects. That is because Python supports Polymorphism.

    Example

    #list
    employee = ['Rohan', 'Jay', 'Aman', 'Ravi', 'Shiv']
    
    #string
    message = 'welcome back to office'
    
    #dictionary
    jobs = {'Sales':3, 'IT':5, 'Management':2, 'Executive':1}
    
    #count the list items
    print("List count: ", len(employee))
    
    #count the string characters
    print('String Chracters count: ', len(message))
    
    #count the dictionary keys
    print('Dictionary Key Counts: ', len(jobs))

    Output

    List count:  5
    String Chracters count:  22
    Dictionary Key Counts:  4

    How does Python Polymorphism work with Inheritance (Method Overriding)?

    Mainly when it comes to class and objects we often use Polymorphism with Python inheritance . In Inheritance, the child or derived class can inherit the properties such as attributes, methods, and other data members from its parent or base class.

    In method overriding, we first redefine a method in the child class with the same method name as the parent class. In method overriding, the inheriting of parent class methods in the child class is the concept of inheritance, and redefining the method with the same name is the concept of Polymorphism. This is how method overriding is a combination of two powerful object-oriented features.

    Benefits of Method overriding

    1. Sometimes in inheritance, the parent class method does not satisfy the child class's functionality. We can extend the functionality by redefining the same method in the child class using method overriding.
    2. In multiple inheritances many child classes inherit from the single parent class, in that case, we can have method overriding in the child classes because there are solid chances that the parent class method does not fulfill all the requirements of all the child classes.

    Example

    Let’s write a Python program that demonstrates method overriding.

    class Automobile():
        def __init__(self, name, price, speed, gear):
            self.name = name
            self.price = price
            self.speed = speed
            self.gears = gear
    
        def details(self):
            print("Vehicle Name:", self.name)
            print("Vehicle Price:", self.price)
            print("Vehicle max Speed:", self.speed)
            print("Vehicle total gears:", self.gears)
    
        def speed_detail(self):
            print("The Max Speed of the vehical is 120 Km/h")
    
        def gears_detail(self):
            print("This Vehicle has 5 gears")
    
    #inherit the automobile class
    class Car(Automobile):
        #speed method overriding
        def speed_detail(self):
            print(f"The Max Speed of this car is {self.speed} Km/h")
            
        #gears method overriding
        def gears_detail(self):
            print(f"This car has {self.gears} gears including reverse")
    
    #inherit the automobile class
    class Bike(Automobile):
        #speed method overriding
        def speed_detail(self):
            print(f"The Max Speed of this Bike is {self.speed} Km/h")
    
        #gears method overriding
        def gears_detail(self):
            print(f"This Bike has {self.gears} gears")
    
    #Create the Car object
    bmw = Car('BMW 3 Series', '44.86 Lakhs' ,'250', 'Automatic 8 Gear Box' )
    bmw.details()  #call the parent details method 
    bmw.speed_detail()     #call the overriden method
    bmw.gears_detail()     #call the overriden method
    
    print("\n\n")
    
    #Create the Bike object
    ktm = Bike('KTM 1190 RC8 R', '20 Lakhs', '280', '6' )
    ktm.details()  #call the parent details method 
    ktm.speed_detail()     #call the overriden method
    ktm.gears_detail()     #call the overriden method

    Output

    Vehicle Name: BMW 3 Series
    Vehicle Price: 44.86 Lakhs
    Vehicle max Speed: 250
    Vehicle total gears: Automatic 8 Gear Box
    The Max Speed of this car is 250 Km/h
    This car has Automatic 8 Gear Box gears including reverse
    
    Vehicle Name: KTM 1190 RC8 R
    Vehicle Price: 20 Lakhs
    Vehicle max Speed: 280
    Vehicle total gears: 6
    The Max Speed of this Bike is 280 Km/h
    This Bike has 6 gears

    Built-in method overriding in Python

    The code for built-in methods like abs(), len(), sum(), etc has already been written in the core Python <class object>. And by default, every class inherits the core Python object. We can see it by applying the mro() method to any class name. To override these inbuilt methods we can redefine their dunder methods for any custom class.

    Example

    class Orders:
        def __init__(self):
            self.cart = {'in process':[], 'canceled':[]}
    
        def buy(self, item):
            self.cart['in process'].append(item)
    
        #override the len() function for Orders() objects
        def __len__(self):
            return len(self.cart['in process'])
    
    my_orders = Orders()
    my_orders.buy('Shoes')
    my_orders.buy('Jackets')
    
    #len function on my_orders object
    in_process= len(my_orders)
    
    print("Total Items in process", in_process)

    Output

    Total Items in process 2

    In the above example, we override the inbuilt len() function for the Orders() class and every time we call the len() function on any of the Orders() object it will invoke the overridden method.

    How Python Polymorphism in Class Methods works

    When we create an object of Python and call a method on that object, Python links that objects with the method during the runtime. Python checks look for the method using Method Resolution Order, which is a technique used by Python objects to call the correct method or other attributes defined in the class. Let’s say we have two different classes, and they both have methods with the same names. When we create the objects for both the classes and call those methods, Python will link the correct object with the correct method.

    Example

    class Car():
        def max_speed(self):
            print("The Max Speed of Car is 350 KM/H")
    
    class Bike():
        def max_speed(self):
            print("The Max Speed of Bike is 300 KM/H")
    
    #create an object of Car
    car = Car()
    
    #create an object of bike
    bike = Bike()
    
    #call the max_speed of class Car
    car.max_speed()
    
    #call the max_speed of class Bike
    bike.max_speed()

    Output

    The Max Speed of Car is 350 KM/H
    The Max Speed of Bike is 300 KM/H

    Car and Bike both have the same method names max_speed() in the above example. But the Car’s object car invoked the max_speed() method of Car , and the Bike’s object bike called the max_speed() of the Bike class.

    What is Function Overloading in Python?

    Function overloading is also one example of Polymorphism. In Function overloading, we have different functions of the same names, with different parameters. But unfortunately, Python does not support Function Overloading, this is because Python is an interpreted programming language, it read and executes the code simultaneously.

    If we try to define a new function with the same name and different parameters, it will override the existing function instead of overloading. The function overloading is supported by Static programming languages like C++, C, and Java.

    Example of Function overloading

    def area(shape, radius):
        result = 2 *3.14 *radius*radius
        print("The Area of the given {shape} is: ", result)
    
    #this will override the above area function not overload
    def area(shape, length, width):
        result = length * width
        print(f"The Area of the given {shape} is: ", result)
    
    #this will throw an error if executed 
    #area('circle',10)
    
    area('rectangle, 10, 20)

    Output

    The Area of the given rectangle is:  200

    Method overloading in Python is also not supported . The reason for not supporting method overloading is the same as function overloading.

    What Operator Overloading in Python?

    The operator overloading is an example of OOP’s Polymorphism, in which we can change the default behavior of an operator. The most common example of operator overloading is the Concatenation and Addition operator + . The + operator performs addition when both the values are integer or float, and it performs the string concatenation operation if both the values are of str data type.

    Example

    print(200+300) # 500  (addition)
    
    print('200'+'300') #200300 (concatenation)

    The above example demonstrates the inbuilt operator overloading of the + operator. But with Python operator overloading , we can change the default behavior of the operator for the class objects. To Overload the operators for class, we use the operator Magic Method, also known as the dunder method. Here is the list of all the operators and their dunder methods.

    Operator Dunder Methods
    + __add__(self, other)
    - __sub__(self, other)
    * __mul __ (self, other)
    / __div__(self, other)
    // __floordiv__(self,other)
    % __mod__(self, other)
    ** __pow__(self, other)
    += __iadd__(self, other)
    -= __isub__(self, other)
    *= __imul__(self, other)
    /+ __idiv__(self, other)
    %= __imod__(self, other)
    **= __ipow__(self, other)
    < __lt__(self, other)
    > __gt__(self, other)
    <= __le__(self, other)
    >= __ge__(self, other)
    == __eq__(self, other)
    != __ne__(self, other)

    Example 1: Overload the + operator for custom class object

    Most operators require two operands to operate, so does the + operator. To overload the + operator for our custom class, we need to define the __add__() method in the Class. The __add__() method represent the + operator operation .

    Example

    class Products:
    
        def __init__(self, items):
            self.items = items
    
        #here self is the object on the left side of + operator
        # and other is the object on the right side of the + operator
        def __add__(self, other):
            return self.items + other.items
    
    home = Products(200)
    office = Products(400)
    
    print("The total Products are:", home + office)

    Output

    The total Products are: 600
    Note : The above home + office statement is equivalent to home.__add__(office) .

    Example 2: Overload the > operator for custom class object

    Similar to the addition overloading, we can overload the greater than > operator with __gt__() method.

    class Products:
        def __init__(self, items):
            self.items = items
    
        #here self is the object on the left side of + operator
        # and other is the object on the right side of the + operator
        def __gt__(self, other):
            return self.items > other.items
    
    home = Products(200)
    
    office = Products(400)
    
    print("home > office = ", home > office)

    Output

    home > office =  False

    Conclusion

    Polymorphism in Python allows performing method overriding and operator overloading, and it is one of the important properties of Object-Oriented Programming. With Polymorphism, an operator can have multiple behaviors with various data types or overload the operator's default behavior.

    In this tutorial, we discussed Polymorphism in Python with the help of some examples. If you like this article or have any questions, please share your comments in the comment section down below.

    People are also reading:

    FAQs


    It lets us perform a single task in multiple ways.

    Method overloading is the run-time polymorphism.

    No, Python does not support function overloading.

    There are two types of polymorphism in OOPs: 1. Static Binding or Compile-Time Polymorphism 2. Dynamic Bindin or Runtime Polymorphism.

    An example of compile-time polymorphism is method overloading, while an example of runtime polymorphism is method overriding.

    Leave a Comment on this Post

    0 Comments