# Operator Overloading in Python

## Operator Overloading #

Operator Overloading lets you redefine the meaning of operator respective to your class. It is the magic of operator overloading that we were able to use to `+`

operator to add two numbers objects, as well as two string objects.

```
>>>
>>> 10 + 400
410
>>>
>>> "ten" + "sor"
'tensor'
>>>
```

Here `+`

operator has two interpretations. When used with numbers it is interpreted as a addition operator whereas with strings it is interpreted as concatenation operator. In other words, we can say that `+`

operator is overloaded for `int`

class and `str`

class.

So how do we redefine or overload an operator for a particular class ?

Operator Overloading is achieved by defining a special method in the class definition. The names of these methods starts and ends with double underscores (`__`

). The special method used to overload `+`

operator is called `__add__()`

. Both `int`

class and `str`

class implements `__add__()`

method. The `int`

class version of the `__add__()`

method simply adds two numbers whereas the `str`

class version concatenates the string.

If the expression is for the form `x + y`

, Python interprets it as `x.__add__(y)`

. The version of `__add__()`

method called depends upon the type of `x`

and `y`

. If `x`

and `y`

are `int`

objects then `int`

class version of `__add__()`

is called. On the other hand, if `x`

and `y`

are list objects then `list`

class version of `__add__()`

method is called.

```
>>>
>>> x, y = 10, 20
>>>
>>> x + y
30
>>> x.__add__(y) # same as x + y
30
>>>
>>> x, y = [11, 22], [1000, 2000]
>>>
>>> x.__add__(y) # same as x + y
[11, 22, 1000, 2000]
>>>
```

The following table lists operator and it's corresponding special method. Recall from lesson Objects and Classes in Python that the variables names which have two leading underscores are private variables, special methods listed in table are not private because they in addition to leading underscores they also have trailing underscores.

Operator | Special Method | Description |
---|---|---|

`+` |
`__add__(self, object)` |
Addition |

`-` |
`__sub__(self, object)` |
Subtraction |

`*` |
`__mul__(self, object)` |
Multiplication |

`**` |
`__pow__(self, object)` |
Exponentiation |

`/` |
`__truediv__(self, object)` |
Division |

`//` |
`__floordiv__(self, object)` |
Integer Division |

`%` |
`__mod__(self, object)` |
Modulus |

`==` |
`__eq__(self, object)` |
Equal to |

`!=` |
`__ne__(self, object)` |
Not equal to |

`>` |
`__gt__(self, object)` |
Greater than |

`>=` |
`__ge__(self, object)` |
Greater than or equal to |

`<` |
`__lt__(self, object)` |
Less than |

`<=` |
`__le__(self, object)` |
Less than or equal to |

`in` |
`__contains__(self, value)` |
Membership operator |

`[index]` |
`__getitem__(self, index)` |
Item at index |

`len()` |
`__len__(self)` |
Calculate number of items |

`str()` |
`__str__(self)` |
Convert object to a string |

Notice that that last two items in table are not operators instead they are built-in functions. But if you want to use then with your class you should define their respective special methods.

The following program first perform an operation using an operator and then it performs the same operation using the corresponding special method.

**python101/Chapter-17/special_methods.py**

```
x, y = 2, 4
print("x = ", x, ", y =", y)
print("\nx + y =", x + y)
print("x.__add__(y) =", x.__add__(y)) # same as x + y
print("\nx * y = ", x * y)
print("x.__mul__(y) = ", x.__mul__(y)) # same as x * y
print("\nx / y = ", x / y)
print("x.__truediv__(y) = ", x.__truediv__(y)) # same as x / y
print("\nx ** y = ", x ** y)
print("x.__pow__(y) = ", x.__pow__(y)) # same as x ** y
print("\nx % y = ", x % y)
print("x.__mod__(y) = ", x.__mod__(y)) # same as x % y
print("\nx == y = ", x == y)
print("x.__eq__(y) = ", x.__eq__(y)) # same as x == y
print("\nx != y = ", x != y)
print("x.__ne__(y) = ", x.__ne__(y)) # same as x != y
print("\nx >= y = ", x >= y)
print("x.__ge__(y) = ", x.__ge__(y)) # same as x >= y
print("\nx <= y = ", x <= y)
print("x.__le__(y) = ", x.__le__(y)) # same as x <= y
print("------------------------------------------")
str1 = "special methods"
print("\nstr1 =", str1)
print("\n'ods' in str1 =", "ods" in str1)
print("str1.__contains__('ods') =", str1.__contains__("ods")) # same as "ods" in str1
print("\nlen(str1) =", len(str1))
print("str1.__len__() =", str1.__len__()) # same as len(str1)
print("------------------------------------------")
list1 = [11,33, 55]
print("\nlist1 =", list1)
print("\nlist1[1] =", list1[1])
print("list1.__getitem(1) =", list1.__getitem__(1)) # same as list1[1]
print("str(list1) =",str(list1)) # same as list1.__str__()
```

**Output:**

```
x = 2 , y = 4
x + y = 6
x.__add__(y) = 6
x * y = 8
x.__mul__(y) = 8
x / y = 0.5
x.__truediv__(y) = 0.5
x ** y = 16
x.__pow__(y) = 16
x % y = 2
x.__mod__(y) = 2
x == y = False
x.__eq__(y) = False
x != y = True
x.__ne__(y) = True
x >= y = False
x.__ge__(y) = False
x <= y = True
x.__le__(y) = True
------------------------------------------
str1 = special methods
'ods' in str1 = True
str1.__contains__('ods') = True
len(str1) = 15
str1.__len__() = 15
------------------------------------------
list1 = [11, 33, 55]
list1[1] = 33
list1.__getitem(1) = 33
str(list1) = [11, 33, 55]
```

The following program demonstrates how we can override operators in a class.

**python101/Chapter-17/point.py**

```
import math
class Point:
def __init__(self, x=0, y=0):
self.__x = x
self.__y = y
# get the x coordinate
def get_x(self):
return self.__x
# set the x coordinate
def set_x(self, x):
self.__x = x
# get the y coordinate
def get_y(self):
return self.__y
# set the y coordinate
def set_y(self, y):
self.__y = y
# get the current position
def get_position(self):
return self.__x, self.__y
# change x and y coordinate by a and b
def move(self, a, b):
self.__x += a
self.__y += b
# overloading + operator
def __add__(self, point_obj):
return Point(self.__x + point_obj.__x, self.__y + point_obj.__y)
# overloading - operator
def __sub__(self, point_obj):
return Point(self.__x - point_obj.__x, self.__y - point_obj.__y)
# overloading < operator
def __lt__(self, point_obj):
return math.sqrt(self.__x ** 2 + self.__y ** 2) < math.sqrt(point_obj.__x ** 2 + point_obj.__y ** 2)
# overloading <= operator
def __le__(self, point_obj):
return math.sqrt(self.__x ** 2 + self.__y ** 2) <= math.sqrt(point_obj.__x ** 2 + point_obj.__y ** 2)
# overloading > operator
def __gt__(self, point_obj):
return math.sqrt(self.__x ** 2 + self.__y ** 2) > math.sqrt(point_obj.__x ** 2 + point_obj.__y ** 2)
# overloading >= operator
def __ge__(self, point_obj):
return math.sqrt(self.__x ** 2 + self.__y ** 2) >= math.sqrt(point_obj.__x ** 2 + point_obj.__y ** 2)
# overloading == operator
def __eq__(self, point_obj):
return math.sqrt(self.__x ** 2 + self.__y ** 2) == math.sqrt(point_obj.__x ** 2 + point_obj.__y ** 2)
## overriding __str__ function
def __str__(self):
return "Point object is at: (" + str(self.__x) + ", " + str(self.__y) + ")"
p1 = Point(4, 6)
p2 = Point(10, 6)
print("Is p1 < p2 ?", p1 < p2) # p1 < p2 is equivalent to p1.__lt__(p2)
print("Is p1 <= p2 ?", p1 <= p2) # p1 <= p2 is equivalent to p1.__le__(p2)
print("Is p1 > p2 ?", p1 > p2) # p1 > p2 is equivalent to p1.__gt__(p2)
print("Is p1 >= p2 ?", p1 >= p2) # p1 >= p2 is equivalent to p1.__ge__(p2)
print("Is p1 == p2 ?", p1 == p2) # p1 < p2 is equivalent to p1.__eq__(p2)
p3 = p1 + p2 # p1 + p2 is equivalent to p1.__add__(p2)
p4 = p1 - p2 # p1 - p2 is equivalent to p1.__sub__(p2)
print() # print an empty line
print(p1) # print(p1) is equivalent to print(p1.__str__())
print(p2) # print(p2) is equivalent to print(p2.__str__())
print(p3) # print(p3) is equivalent to print(p3.__str__())
print(p4) # print(p4) is equivalent to print(p4.__str__())
```

**Output:**

```
Is p1 < p2 ? True
Is p1 <= p2 ? True
Is p1 > p2 ? False
Is p1 >= p2 ? False
Is p1 == p2 ? False
Point object is at: (4, 6)
Point object is at: (10, 6)
Point object is at: (14, 12)
Point object is at: (-6, 0)
```

The `Point`

class defines two private attributes `__x`

and `__y`

which represent `x`

and `y`

coordinates in a plane. Then it defines getter and setter methods for those attributes. It also defines, `get_position()`

and `move()`

method to get the current position and change coordinates respectively.

In line 35, we have overloaded `+`

operator for the `Point`

class. The `__add__()`

method creates a new `Point`

object by adding individual coordinates of one `Point`

object to another Point object. Finally, it returns the newly created object to it's caller. This allows us to write expressions like:

```
p3 = p1 + p2
```

where `p1`

, `p2`

and `p3`

are three Point objects.

Python interprets the above expression as `p3 = p1.__add__(p2)`

, and calls the `__add__()`

method to add two `Point`

objects. The return value from the `__add__()`

method is then assigned to `p3`

. It is important to note that when `__add__()`

method is called, the value of `p1`

is assigned to the `self`

parameter and the value of `p2`

is assigned to the `point_obj`

parameter. The rest of the special methods works in the similar fashion.