JavaRush /Курси /Модуль 1: Python Core /Перевантаження операторів

Перевантаження операторів

Модуль 1: Python Core
Рівень 11 , Лекція 5
Відкрита

6.1 Магічні методи

Перевантаження операторів в Python дозволяє визначити або змінити поведінку вбудованих операторів (наприклад, +, -, *, /) для користувацьких класів. Це робиться за допомогою спеціальних методів, котрі також називаються магічними методами.

Наприклад, у своєму класі ви можете перевантажити оператори порівняння:

Оператор Метод без підкреслення Сигнатура метода
== eq() __eq__(self, other)
!= ne() __ne__(self, other)
< lt() __lt__(self, other)
<= le() __le__(self, other)
> gt() __gt__(self, other)
>= ge() __ge__(self, other)

Припустимо, ви написали свій клас і хочете, щоб об'єкти вашого класу порівнювались саме так, як вам це потрібно. Вам потрібно просто реалізувати в вашому класі метод «__eq__», і Python буде викликати його кожного разу, коли в коді порівнюються об'єкти вашого класу.

Приклад:


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
        
# Використання
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1 == v2)  # Виведе: True
print(v1 == v3)  # Виведе: False

Кожного разу, коли ви порівнюєте два ваші об'єкти, Python перевіряє, а чи є у них реалізована функція «__eq__». Якщо є, то викликає її. А якщо її немає, то просто буде порівнювати посилання на об'єкти.

Фактично в прикладі вище написано (тільки ще перевірку на наявність метода треба додати):


# Використання
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2))  # Виведе: True
print(v1.__eq__(v3))  # Виведе: False

6.2 Список всіх операторів

Всього для перевантаження доступно 6 груп операторів.

Арифметичні оператори:

Оператор Метод без підкреслення Сигнатура метода
+ 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)

Оператори порівняння:

Оператор Метод без підкреслення Сигнатура метода
== eq __eq__(self, other)
!= ne __ne__(self, other)
< lt __lt__(self, other)
<= le __le__(self, other)
> gt __gt__(self, other)
>= ge __ge__(self, other)

Логічні оператори:

Оператор Метод без підкреслення Сигнатура метода
& and __and__(self, other)
| or __or__(self, other)
^ xor __xor__(self, other)
~ invert __invert__(self)

Оператори індексації та зрізів:

Оператор Метод
obj[key] __getitem__(self, key)
obj[key] = value __setitem__(self, key, value)
del obj[key] __delitem__(self, key)

Унарні оператори:

Оператор Метод
- __neg__(self)
+ __pos__(self)
abs() __abs__(self)
~ __invert__(self)

Оператори присвоєння:

Оператор Метод
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

Можливо, саме тому Python такий повільний – кожного разу перед виконанням оператора він шукає аналогічну функцію у класу та всіх його класів-батьків. Зате це дозволяє писати найкомпактніший код у світі :)

6.3 Оператор індексації

Те, що можна порівнювати об'єкти або вичитувати множини – це в якомусь сенсі очевидно. І ви самі здогадаєтесь про це, якщо будете писати клас, що передбачає над ним логічні чи математичні операції.

Хочу з вами розглянути такий цікавий приклад – як оператор індексації. Давайте одразу почнемо з коду прикладу:


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)
        
# Використання
c_list = CustomList([1, 2, 3, 4, 5])
print(c_list[1])  # Виведе: 2
c_list[1] = 10
print(c_list)  # Виведе: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list)  # Виведе: [1, 3, 4, 5]

Тут ми бачимо приклад трьох операцій:

  • Читання даних через індекс.
  • Запис даних через індекс.
  • І навіть видалення даних через індекс.

А взагалі не обов'язково, що дані всередині будуть зберігатися у вигляді списку. Або індекс не обов'язково має бути числом. Наприклад, клас dictionary (словник) саме так і реалізований.

Створюємо SuperList

Пам'ятаєте клас list? Йому можна присвоювати елементи, але тільки з тими індексами, що вже існують. Давайте зробимо свій клас, назвемо його SuperList, до елементів якого можна буде звертатися по будь-якому індексу:

  • Якщо індекс < 0, то будемо вставляти елемент на початок.
  • Якщо індекс >= len, то будемо додавати елемент в кінець.
  • В інших випадках просто повертати елемент.

Приклад:


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]

Отож перевантаження індексів — крута можливість, і я раджу користуватися нею на практиці. А на сьогодні — все.

Коментарі (1)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Andriy Trubchanin Рівень 23
2 березня 2025
Лекція "Перевантаження операторів" в розділі "Стандартні помилки". Структура курсу поїхала.