Operator Overloading in Python
Last updated on September 22, 2020
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.
1 2 3 4 5 6 7 | >>>
>>> 10 + 400
410
>>>
>>> "ten" + "sor"
'tensor'
>>>
|
Here +
operator has two interpretations. When used with numbers it is interpreted as an 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 the +
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 the __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 the list
class version of the __add__()
method is called.
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>>
>>> 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 the 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 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:
1 2 3 4 5 6 7 8 9 10 | 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.
Load Comments