CodeGym /Java Course /Python SELF EN /Operator Overloading

Operator Overloading

Python SELF EN
Level 20 , Lesson 0
Available

6.1 Magic Methods

Operator overloading in Python allows you to define or change the behavior of built-in operators (like +, -, *, /) for custom classes. This is done using special methods, which are also called magic methods.

For example, in your class you can overload comparison operators:

Operator Method without underscores Method Signature
== eq() __eq__(self, other)
!= ne() __ne__(self, other)
< lt() __lt__(self, other)
<= le() __le__(self, other)
> gt() __gt__(self, other)
>= ge() __ge__(self, other)

Suppose you wrote your own class and you want the objects of your class to be compared exactly the way you need. You just need to implement the «__eq__» method in your class, and Python will call it every time objects of your class are compared in the code.

Example:


class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
        
# Usage
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1 == v2)  # Outputs: True
print(v1 == v3)  # Outputs: False

Every time you compare two of your objects, Python checks if they have an implemented function «__eq__». If there is, it calls it. If not, it will just compare the references to the objects.

In fact, the example above is written (just need to add a check for the method's existence):


# Usage
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2))  # Outputs: True
print(v1.__eq__(v3))  # Outputs: False

6.2 List of All Operators

There are a total of 6 groups of operators available for overloading.

Arithmetic Operators:

Operator Method without underscores Method Signature
+ add __add__(self, other)
- sub __sub__(self, other)
* mul __mul__(self, other)
/ truediv __truediv__(self, other)
// floordiv __floordiv__(self, other)
% mod __mod__(self, other)
** pow __pow__(self, other)

Comparison Operators:

Operator Method without underscores Method Signature
== eq __eq__(self, other)
!= ne __ne__(self, other)
< lt __lt__(self, other)
<= le __le__(self, other)
> gt __gt__(self, other)
>= ge __ge__(self, other)

Logical Operators:

Operator Method without underscores Method Signature
& and __and__(self, other)
| or __or__(self, other)
^ xor __xor__(self, other)
~ invert __invert__(self)

Indexing and Slicing Operators:

Operator Method
obj[key] __getitem__(self, key)
obj[key] = value __setitem__(self, key, value)
del obj[key] __delitem__(self, key)

Unary Operators:

Operator Method
- __neg__(self)
+ __pos__(self)
abs() __abs__(self)
~ __invert__(self)

Assignment Operators:

Operator Method
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

Maybe that's why Python is slow – every time before executing an operator, it looks for a corresponding function in the class and all its parent classes. But this allows for the most compact code in the world :)

6.3 Indexing Operator

That you can compare objects or subtract sets is somewhat obvious. And you'll figure it out yourself if you're writing a class that implies logical or mathematical operations on it.

Let's go over an interesting example – the indexing operator. Let's jump straight into the code example:


class CustomList:
    def __init__(self, data):
        self.data = data
        
    def __getitem__(self, index):
        return self.data[index]
        
    def __setitem__(self, index, value):
        self.data[index] = value
        
    def __delitem__(self, index):
        del self.data[index]
        
    def __repr__(self):
        return repr(self.data)
        
# Usage
c_list = CustomList([1, 2, 3, 4, 5])
print(c_list[1])  # Outputs: 2
c_list[1] = 10
print(c_list)  # Outputs: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list)  # Outputs: [1, 3, 4, 5]

Here we see an example of three operations:

  • Reading data through an index
  • Writing data through an index
  • And even deleting data through an index.

And it’s not at all necessary for the data inside to be stored as a list. Or that the index must be a number. For example, the dictionary class is implemented just like that.

Creating a SuperList

Remember the list class? You can assign elements to it, but only with indices that already exist. Let's create our own class, call it SuperList, where you can access elements with any index:

  • If the index < 0, we'll insert the element at the beginning
  • If the index >= len, we'll add the element at the end
  • In other cases, just return the element

Example:


class SuperList(list):
    def __init__(self, value):
        super().__init__(value)
        
    def __setitem__(self, index, value):
        if index >= len(self):
            super().append(value)
        elif index < 0:
            super().insert(0, value)
        else:
            super().__setitem__(index, value)
        
lst = SuperList([1, 2, 3])
lst[200] = 100
lst[-200] = 99
print(lst)  # [99, 1, 2, 3, 100]

So, overloading indices is a great opportunity, and I recommend using it in practice. That's it for today.

2
Task
Python SELF EN, level 20, lesson 0
Locked
Overloading comparison operators
Overloading comparison operators
2
Task
Python SELF EN, level 20, lesson 0
Locked
Overloading Indexing Operators
Overloading Indexing Operators
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION