Занятие №19:
Перегрузка операторов


Основные понятия

Определение
Перегрузка операторов - изменение логики работы различных операторов языка с использованием специальных методов. Эти методы идентифицируются двойным подчеркиванием до и после имени метода.
Под операторами имеются в виду знаки +, -, *, /, отвечающие за выполнение привычных математических операций, а также особенности синтаксиса языка, обеспечивающие создание объекта, вызова его как функции, получение доступа к элементу объекта по индексу и т. д. К перегружаемым операторам также относятся >, <, ≤, ≥, ==, !=, +=, -=.
Простой пример
class Number:
def __init__(self, value):
self.data = value
def __add__(self, other):
return Number(self.data + other)
a = Number(12)
b = a + 4
b.data16
Некоторые методы перегрузки операций
| Метод | Что реализует | Зачем вызывается |
|---|---|---|
| __init__ | Конструктор | Создание объекта a = Class(args) |
| __del__ | Деструктор | Уничтожение объекта |
| __add__ | Операция + | a + b |
| __sub__ | Операция - | a - b |
| __mul__ | Операция * | a * b |
| __getitem__ | Индексирование, срезы | X[i], X[i:j] |
| __setitem__ | Присваивание по индексу | X[i] = value, X[i:j] = value |
| __len__ | Длина | len(X) |
| __bool__ | Булевские проверки | bool(X) |

Внутреннее устройство операций
Если есть встроенная функция func() и соответствующий специальный метод для функции __func__(), Python интерпретирует вызов функции как obj.__func__(), где obj - это объект. В случае с операторами, если у вас есть оператор opr и соответствующий специальный метод для него __opr__(), Python интерпретирует выражение obj1 <opr> obj2 как obj1.__opr__ (obj2) .
Пример
class StarSystem:
def __init__(self, planets, name):
self.planets = list(planets)
self.name = name
def __len__(self):
return len(self.planets)
def __add__(self, other):
planets_1 = self.planets.copy()
planets_1.append(other)
return StarSystem(planets_1, self.name)Пример
system = StarSystem(['planet1', 'planet2', 'planet3'], 'StarSystem1')
len(system)
system = system + 'planet4'
system.planets3
['planet1', 'planet2', 'planet3', 'planet4']Небольшое замечание

Помните, что не существует преимущества в скорости, если исключить посредника и вызвать метод напрямую.
| Список | Вызов метода | Время |
|---|---|---|
| L = list(range (100)) | x = L. __ len __ () | 0.134 |
| L = list(range (100)) | x = len(L) | 0.063 |
Операторы radd и iadd
class Number1:
def __init__ (self, val):
self.val = val
def __add__ (self, other):
print('add', self.val, other)
return self.val + other
# __radd__ = __add__
def __radd__ (self, other):
print (' radd ', self.val, other)
return other + self.val
# return self.__add__(other)
# return self.val + otherОператоры radd и iadd
x = Number1(32)
y = Number1(25)
x + 1
2 + y
x + yadd 32 1
33
radd 25 2
27
add 32 <__main__.Commuterl object at 0x0000015BF3EE90F0>
radd 25 32
57Операторы radd и iadd
class StarSystem:
def __init__(self, planets, name):
self.planets = list(planets)
self.name = name
def __add__(self, other):
planets_1 = self.planets.copy()
planets_1.append(other)
return StarSystem(planets_1, self.name)
def __radd__(self, other):
planets_1 = self.planets.copy()
planets_1.insert(0, other)
return StarSystem(planets_1, self.name)Операторы radd и iadd
system_1 = StarSystem(['planet_1'], 'System_1')
system_1 = system_1 + 'planet_2'
system_1.planets
system_1 = 'planet_3' + system_1
system_1.planets['planet_1', 'planet_2']
['planet_3', 'planet_1', 'planet_2']Операторы radd и iadd
class StarSystem:
def __init__(self, planets, name):
self.planets = list(planets)
self.name = name
def __iadd__(self, other):
self.planets.append(other)
return self
system_1 = StarSystem(['planet_1'], 'System_1')
system_1 += 'planet_2'
system_1.planets['planet_1', 'planet_2']Оператор bool
class StarSystem:
def __init__(self, planets, name):
self.planets = list(planets)
self.name = name
def __bool__(self):
return len(self.planets) > 0
system_1 = StarSystem(['planet_1, planet_2'], 'System_1')
system_2 = StarSystem([], 'System_2')
bool(system_1)
bool(system_2)True
FalseОператор str
class StarSystem:
def __init__(self, planets, name):
self.planets = list(planets)
self.name = name
def __str__(self):
return f'Название системы {self.name} \
и её планеты {[i for i in self.planets]}'Оператор str
system_1 = StarSystem(['planet_1', 'planet_2'], 'System_1')
print(system_1)Название системы System_1 и её планеты ['planet_1', 'planet_2']Оператор getitem
class StarSystem:
def __init__(self, planets, name):
self.planets = list(planets)
self.name = name
def __getitem__(self, key):
return self.planets[key]
system_1 = StarSystem(['planet_1', 'planet_2'], 'System_1')
system_1[0]
system_1[0:2]'planet_1'
['planet_1', 'planet_2']Правила использования перегрузки операторов
- Используйте перегрузку при создании своих классов со специальными методами. Также для классов, наследуемых от абстрактных классов;
- Перегружайте операторы, если это естественно, ожидаемо и не имеет каких-либо побочных эффектов;
- Не перегружайте операторы просто так. Делайте код максимально удобным, эффективным и читабельным.

Спасибо за понимание!

Лекция №19. Перегрузка операторов
By Protectornaldo
Лекция №19. Перегрузка операторов
- 83