Python: Operator Overloading

Most of the programming languages including Python have some operators to use in the calculation such as adding and subtractions but these operators can get confused when it is used in class or object-oriented programming so this tutorial will show you how to use them to make calculations in instances.

Table of Contents

What is Operator Overloading?

When you want to add two instances that are created under the same class the python interpreter will give you an error and doesn’t understand what the “+” add operator means in that case and here comes the definition of overloading the operator.

Python developers have come with some built-in functions called magic functions that will tell python what are those operators and how to deal with them when you make calculations in instances. Let us use the add operator to add two objects and see what error you will get:

class Car:
    def __init__(self, price):
        self.price = price
        
c1 = Car(10)
c2 = Car(20)
print(c1 + c2)

When you run the code in your Jupyter Notebook or any IDE you will get an error telling you “TypeError: unsupported operand type(s) for +: ‘Car’ and ‘Car’” and that means it couldn’t recognize what is that add operator is so to fix this problem using some magic functions.

Python Special Functions

Special python functions are not the functions that are defined by the developer instead they are built-in python to make things easier and help you speed your python development process.

Every function that starts and ends with “__” double scores are considered special functions and maybe you’ve noticed that we’ve already used one of them which is “__init__” and this is the magic function. Let’s now try to print the objects (instances) and see what you get:

class Car:
    def __init__(self, price):
        self.price = price
        
c1 = Car(10)
c2 = Car(20)
print(c1)
print(c2)

Executing the code will show you the memory locations of each car instance (object) and not the actual price for that particular object so now we can use the magic functions to print the car price. Let’s modify the code and run it again:

class Car:
    def __init__(self, price):
        self.price = price
        
    def __str__(self):
        return "{}".format(self.price)
        
c1 = Car(10)
c2 = Car(20)
print(c1)
print(c2)

We’ve used the “__str__” magic function we could get the actual price for every car and we can now use these magic functions to tell the python interpreted (compiler) how to use the operators on the instance level.

We can actually add them without using the python overloaded operator and this example will show you how you can perform that:

class Car:
    def __init__(self, price):
        self.price = price
        
c1 = Car(10)
c2 = Car(20)
TotalPrice = c1.price + c2.price
print(TotalPrice)

When you execute the code it will give you the number 30 which is the result that we want to get but this is not the right way to perform this kind of operation and here comes the power of using the magic functions and operator overloading.

Overloading Python Operators

There is a magic function for every mathematic calculation like adding, subtraction, multiplication, and much more and we will explore most of them in this short tutorial and let us start with the most basic one which is the “__add__” adding magic function:

class Car:
    def __init__(self, price):
        self.price = price
        
    def __add__(self, other):
        return self.price + other.price
        
c1 = Car(10)
c2 = Car(20)
c3 = c1 + c2
print(c3)

When you execute the code you will see the number 30 printed and this is the result of adding the two prices of the cars instances. 

The “__add__” magic function accepts two-argument the “self” is the price of the first instance and the second one “other” is the rest of the car’s price in this case. Let us now see the other magic functions for the subtraction operation:

class Car:
    def __init__(self, price):
        self.price = price
def __sub__(self, other):
        return self.price - other.price
        
c1 = Car(10)
c2 = Car(20)
c3 = c2 - c1
print(c3)

The “__sub__” magic function which stands for subtraction is responsible to make the subtraction operation and you will get the 10 as a result. Let’s see another operation which is the multiplication:

class Car:
    def __init__(self, price):
        self.price = price
def __mul__(self, other):
        return self.price * other.price
        
c1 = Car(10)
c2 = Car(20)
c3 = c2 * c1
print(c3)

Again the function is “__mul__” which stands for multiplication is responsible for the multiplication operation in the above example. 

We will explore more about the other magic functions for the mathematical operation like the division:

class Car:
    def __init__(self, price):
        self.price = price
def __truediv__(self, other):
        return self.price / other.price
        
c1 = Car(10)
c2 = Car(20)
c3 = c2 / c1
print(c3)

Now it’s obvious that the “__truediv__” magic function is used for the decision. The “__pow__” is used for the power:

class Car:
    def __init__(self, price):
        self.price = price
def __pow__(self, other):
        return self.price ** other.price
        
c1 = Car(10)
c2 = Car(20)
c3 = c2 ** c1
print(c3)

You can get the remainder of the division calculation using the “__mod__” modulo operator:

class Car:
    def __init__(self, price):
        self.price = price
def __mod__(self, other):
        return self.price % other.price
        
c1 = Car(10)
c2 = Car(20)
c3 = c1 % c2
print(c3)

The last one in this section is calculating the floor division using the “__floordiv__” magic function:

class Car:
    def __init__(self, price):
        self.price = price
def __floordiv__(self, other):
        return self.price // other.price
        
c1 = Car(10)
c2 = Car(20)
c3 = c2 // c1
print(c3)

Now let us move to another section which is the overloading comparison operations and use them with the if statements.

Overloading Comparison Operators

The developers behind the python language didn’t just add the magic functions for the mathematical operations but also implemented the comparison operations. Let us make an example of how to use them in a real-world scenario:

class Car:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        
    def __lt__(self, other):
        self_car = (self.price * self.quantity)
        other_car = (other.price * other.quantity)
        return self_car < other_car
        
Tesla_Model3 = Car(39.490, 22)
BMW_i8 = Car(147.500, 7)
print(Tesla_Model3 < BMW_i8)

Consider a car dealer that has 22 cars of Tesla model 3 at the price of $39,490 and 7 cars of BMW i8 at the price of $147,500 and he wants to see which one will generate much revenue when he sells all of them. The example above might seems a little bit silly but just to understand how things work when implementing the comparison operator.

So we’ve implemented the “__lt__” less than comparison operator to see which one will generate more and we created two variables in the “__lt__” comparison the first one will calculate the revenue of the tesla model 3 and the second one for the BMW i8 car and will return True if BMW i8 returns more in revenue.

Then we created two objects (instances) of the car class specifying the price of each car and their quantity and the final result will be True. We can use the if statement if you are let’s say building a real-world application that will do a comparison and print something on the screen:

class Car:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        
    def __lt__(self, other):
        self_car = (self.price * self.quantity)
        other_car = (other.price * other.quantity)
        return self_car < other_car
        
Tesla_Model3 = Car(39.490, 22)
BMW_i8 = Car(147.500, 7)
if Tesla_Model3 < BMW_i8:
    print("BMW i8 will generate more revenue")
else:
    print("Tesla Model 3 will generate more revenue")

The code will print the first line because the BMW i8 is obviously generating more revenue. We will keep using the same code above with some adjustment and let’s change the comparison operator and its magic function:

class Car:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        
    def __le__(self, other):
        self_car = (self.price * self.quantity)
        other_car = (other.price * other.quantity)
        return self_car <= other_car
        
Tesla_Model3 = Car(39.490, 22)
BMW_i8 = Car(147.500, 7)
print(Tesla_Model3 <= BMW_i8)

The result will be True since we’ve used the “__le__” less than or equal comparison operator in that example. We can use the “__gt__” greater than in our code as well:

class Car:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        
    def __gt__(self, other):
        self_car = (self.price * self.quantity)
        other_car = (other.price * other.quantity)
        return self_car > other_car
        
Tesla_Model3 = Car(39.490, 22)
BMW_i8 = Car(147.500, 7)
print(Tesla_Model3 > BMW_i8)

The result will be False obviously since Tesla is generating less revenue compared to BMW. Another comparison operator is “__ge__” greater than or equal:

class Car:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        
    def __ge__(self, other):
        self_car = (self.price * self.quantity)
        other_car = (other.price * other.quantity)
        return self_car >= other_car
        
Tesla_Model3 = Car(39.490, 22)
BMW_i8 = Car(147.500, 7)
print(Tesla_Model3 >= BMW_i8)

The result is also the same as the previous one. Now there are other two comparison operators left which are “__eq__” equal to:

class Car:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        
    def __eq__(self, other):
        self_car = (self.price * self.quantity)
        other_car = (other.price * other.quantity)
        return self_car == other_car
        
Tesla_Model3 = Car(39.490, 22)
BMW_i8 = Car(147.500, 7)
print(Tesla_Model3 == BMW_i8)

Execute the code and you will get False as a result and the last comparison operator is “__ne__” not equal to:

class Car:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        
    def __ne__(self, other):
        self_car = (self.price * self.quantity)
        other_car = (other.price * other.quantity)
        return self_car != other_car
        
Tesla_Model3 = Car(39.490, 22)
BMW_i8 = Car(147.500, 7)
print(Tesla_Model3 != BMW_i8)

Since the revenue is not the same then you will get the True as a result when executing the above code.

Conclusion

Python developer has created a lot of overloaded operators not only mentioned in this tutorial but we’ve discussed the most useful ones that you will be using in your development career and when building complex real-world programs.

Leave a Comment

Your email address will not be published. Required fields are marked *