English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
You can change the meaning of operators in Python based on the operands you use. This practice is called operator overloading.
Python operatorsFor built-in classes. But the same operator has different behaviors for different types. For example,+The operator will perform arithmetic addition on two numbers, merge two lists, and connect two strings.
This feature in Python allows the same operator to have different meanings according to the context, which is called operator overloading.
So, what happens when we use them with objects of user-defined classes? Let's look at the following class, which tries to simulate a point in a two-dimensional coordinate system.
class Point: def __init__(self, x = 0, y = 0): self.x = x self.y = y
Now, run the code and try to add two points in the Python shell.
>>> p1 = Point(2,3) >>> p2 = Point(-1,2) >>> p1 + p2 Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'Point' and 'Point'
Wow! There are many errors. TypeError is raised because Python does not know how to add two Point objects together.
The good news is that we can teach Python this through operator overloading. But first, let's understand what special functions are.
Class functions that start with double underscores __ are called special functions in Python. This is because they are not ordinary functions. The __init__() function we defined above is one of them. It is called every time we create a new object of the class. There are many special functions in Python.
Using special functions, we can make our class compatible with built-in functions.
>>> p1 = Point(2,3) >>> print(p1) <__main__.Point object at 0x00000000031F8CC0>
The print output did not reach the expected effect. But if we define the __str__() method in the class, we can control its print output. We add this to our class.
class Point: def __init__(self, x = 0, y = 0): self.x = x self.y = y def __str__(self): return "({0},"1})".format(self.x, self.y)
Now, let's try the function again with print().
>>> p1 = Point(2,3) >>> print(p1) (2,3)
It turns out that it is better when we use the built-in functions str() or format() because they call the same method format().
>>> str(p1) '('2,3) >>> format(p1) '('2,3)
Therefore, when you execute str(p1) or format(p1) is executed, Python internally executes p1.__str__() is called, which is why it is called a special function. Let's continue with operator overloading.
to overload+With the right to overload, we are also given great responsibility. We can do anything we like in this function. But it is wise to return a Point object with the sum of coordinates. We can implement the __add__() function in the class. Having the right also means being given great responsibility. We can do anything we like in this function. But it is wise to return a Point object with the sum of coordinates.
class Point: def __init__(self, x = 0, y = 0): self.x = x self.y = y def __str__(self): return "({0},"1})".format(self.x, self.y) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Point(x, y)
Now, let's try again.
>>> p1 = Point(2,3) >>> p2 = Point(-1,2) >>> print(p1 + p2) (1,5)
What actually happens is, when you execute p1 + p2when Python will call p1 __ add __(p2) which is also Point.__ add __(p1, p2). Similarly, we can overload other operators. The list of special functions we need to implement is as follows.
operator | expression | Internally |
---|---|---|
Addition (+) | p1 + p2 | p1 __ add __(p2) |
Subtraction (-) | p1-p2 | p1 __ sub __(p2) |
Multiplication (*) | p1 * p2 | p1 __ mul __(p2) |
Power (**) | p1 ** p2 | p1 __ pow __(p2) |
Division (/) | p1 / p2 | p1 __ truediv __(p2) |
Floor division (//) | p1 // p2 | p1 __ floordiv __(p2) |
Modulus (%) | p1%p2 | p1 __ mod __(p2) |
Bitwise left shift (<<) | p1 << p2 | p1 __ lshift __(p2) |
Bitwise right shift (>>) | p1 >> p2 | p1 __ rshift __(p2) |
Bitwise AND (and) | p1 and p2 | p1 .__ and __ (p2) |
Bitwise OR (or) | p1 | 2 | p1 .__ or __ (p2) |
Bitwise XOR (^) | p1 ^ p2 | p1 .__ xor __ (p2) |
Bitwise NOT(~) | ~p1 | p1 .__ invert __ () |
Python does not limit operator overloading to arithmetic operators. We can also overload comparison operators.
Suppose, we want to implement the less than operator (<) in the Point class. Let's compare the sizes of these points from the origin and return the result for this purpose. It can be implemented as follows.
class Point: def __init__(self, x = 0, y = 0): self.x = x self.y = y def __str__(self): return "({0},"1})".format(self.x, self.y) def __lt__(self, other): self_mag = (self.x ** 2) + (self.y ** 2) other_mag = (other.x ** 2) + (other.y ** 2) return self_mag < other_mag
Try running these examples in the Python shell.
>> Point(1,1) < Point(-2,-3) True >> Point(1,1) < Point(0.5,-0.2) False >> Point(1,1) < Point(1,1) False
Similarly, the following lists the special functions that we need to implement to overload other comparison operators.
operator | expression | Internal |
---|---|---|
Less than (<) | p1 <p2 | p1 .__ lt __ (p2) |
Less than or equal to (<=) | p1 <= p2 | p1 .__ le __ (p2) |
Equal to (==) | p1 == p2 | p1 .__ eq __ (p2) |
Not equal to (!=) | p1!= p2 | p1 .__ ne __ (p2) |
Greater than (>) | p1> p2 | p1 .__ gt __ (p2) |
Greater than or equal to (>=) | p1>= p2 | p1 .__ ge __ (p2) |