Operator Overloading in Python
In any programming language, + is an arithmetic operator; it adds two numbers to give the sum. Have you ever tried to concatenate two strings? Concatenating two strings is adding two separate strings into a single string, and + is used to achieve this. If we say, “Hi” + “ ” + "people", we will get "Hi people" as the output. To concatenate strings, we use the same operator, which is used to add numbers; this is operator overloading. Also, we can use + to add two lists. It is only one operator-"+", but it behaves differently in different scenarios depending on the data type of the operands. This article discusses Operator overloading in detail with examples.
What is Operator Overloading?
As in method overloading, the same method can show different behavior depending on the number of parameters and the data types of the parameters. Operator overloading works on similar concept if you are aware of method overloading in object-oriented programming. Therefore, the feature in Python that allows an operator to behave differently according to the scenario and the data type of the participating operands is called "Operator overloading".
Note: Remember that we can't create new operators in this feature. We can let an already existing operator work on data types it usually can't.
How to Overload an Operator in Python?
How does the compiler know what to do with it when we use an operator? In Python, every in-built operator has a specific magic function. These are the special functions. Whenever the user uses an operator, the method associated with the operator will be automatically called, and the compiler will understand what to do.
For example, in the case of the addition operator, the + operator's magic function is overloaded by both integer class and string class. Hence, + shows different behavior for objects of integer class and string class objects.
Extending The Capabilities of Operators:
Suppose we have a class and created two objects, obj1, and obj2. If we try to use the + operator to add these two objects, it won't be valid, and the compiler will raise an error because adding two objects is not defined in the __add__ (), which is the magic method of +. It is like calling the method with no logic we need. So, we need to create the logic.
Hence, to extend the operator's functionality, we need to write the logic in the magic method of the operator.
class addition:
def __init__(self, num):
self. num = num
def __add__(self, obj):
return self. num + obj. num
obj1 = addition (2)
obj2 = addition (4)
print ("Sum of the two int objects: ", obj1 + obj2)
obj3 = addition ("Hi")
obj4 = addition ("!")
print ("Sum of two string objects: ", obj3 + obj4)
Output:
Sum of the two int objects: 6
Sum of two string objects: Hi!
Understanding:
Inside the class, you can see the __add__ method, which is the magic function of the addition operator. We are writing the logic to add two objects to the function in the above program.
In the snippet:
def __add__(self, obj):
return self. num + obj. num
When we call + by saying obj1 + obj2, the compiler will automatically invoke this method.
obj1 takes the place of self, and obj2 takes the place of obj:
obj1. num + obj2. num = 2 + 4 = 6 will be the output.
- Let us extend the logic further to add two complex numbers:
class complex_addition:
def __init__(self, real, imag):
self. real = real
self. imag = imag
def __add__(self, obj):
return self. real + obj. real, self. imag + obj. imag
obj1 = complex_addition (3, 4)
obj2 = complex_addition (4, 7)
print ("Sum of the two complex objects: ", obj1 + obj2)
Output:
Sum of the two complex objects: (7, 11)
Understanding:
To add two complex numbers, we have to add the real part of the two numbers and the imaginary part of the two numbers:
A + iB + C + iD = (A + C) + (B + D)i
- The multiplication operator * can be used to multiply two or more numbers, and also, when the operands are of the string class, it can be used for repetition or strings:
7 * 8 = 56
Hi * 4 = HiHiHiHi
Now, let us try to overload the comparison operators:
class comparison:
def __init__(self, num):
self. num = num
def __lt__(self, obj):
if (self. num < obj. num):
return True
else:
return False
def __gt__ (self, obj):
if (self. num > obj. num):
return True
else:
return False
def __eq__ (self, obj):
if (self. num == obj. num):
return True
else:
return False
obj1 = comparison (int (input ("Enter obj1 value: ")))
obj2 = comparison (int (input ("Enter obj2 value: ")))
print ("Is obj1 greater than obj2? ->", obj1 > obj2)
print ("Is obj1 less than obj2? ->", obj1 < obj2)
print ("Is obj1 equal to obj2? ->", obj1 == obj2)
Output:
Enter obj1 value: 4
Enter obj2 value: 2
Is obj1 greater than obj2? -> True
Is obj1 less than obj2? -> False
Is obj1 equal to obj2? -> False
Understanding:
We took the input for the values of two objects from the user. We wrote logic to compare the values using three magic functions of greater than, less than, and equal to operators in the class.
Here is the list of magic functions of a few operators in Python:
- BINARY:
Operator | Operation | Magic method |
+ | Addition | __add__ (self, other) |
- | Subtraction | __sub__ (self, other) |
* | Multiplication | __mul__ (self, other) |
/ | Division | __truediv__ (self, other) |
// | Floor division | __floordiv__ (self, other) |
% | Modulo division | __mod__ (self, other) |
** | Power (Exponent) | __pow__ (self, other) |
>> | Right shift | __rshift__ (self, other) |
<< | Left shift | __lshift__ (self, other) |
& | AND | __and__ (self, other) |
| | OR | __or__ (self, other) |
^ | XOR | __xor__ (self, other) |
- COMPARISON:
Operator | Operation | Magic method |
< | Less than | __lt__ (self, other) |
> | Greater than | __gt__ (self, other) |
<= | Less than or equal to | __le__ (self, other) |
>= | Greater than or equal to | __ge__ (self, other) |
== | Equal to | __eq__ (self, other) |
!= | Not equal to | __ne__ (self, other) |
- UNARY:
Operator | Operation | Magic method |
+ | Positive | __pos__ (self) |
- | Negative | __neg__ (self) |
~ | Complement | __invert__ (self) |
- Assignment:
Operator | Operation | Magic method |
+= | Add and assign | __iadd__ (self, other) |
-= | Subtract and assign | __isub__ (self, other) |
*= | Multiply and assign | __imul__ (self, other) |
/= | Divide and assign | __idiv__ (self, other) |
//= | Floor divide and assign | __ifloordiv__ (self, other) |
%= | Modulo divide and assign | __imod__ (self, other) |
**= | Power and assign | __ipow__ (self, other) |
>>= | Right shift and assign | __irshift__ (self, other) |
<<= | Left shift and assign | __ilshift__ (self, other) |
&= | AND and assign | __iand__ (self, other) |
|= | OR and assign | __ior__ (self, other) |
^= | XOR and assign | __ixor__ (self, other) |
Note:
We cannot change the number of operands of an operator. We cannot make a unary operator binary and vice versa. If we try to do so, the compiler will raise an error.
Example: 6~8 is not valid.
Conclusion:
Every time we use an operator, the magic function associated with the operator will be automatically invoked by the compiler. If we want to extend the operator's functionality, we can overload the function using the inbuilt syntax of the special Python functions.