Перегрузка операторов: реализация собственного поведения через дандер-методы
Почему перегрузка операторов — это мощный инструмент? 🔥
В Python операторы (+, -, *, == и др.) работают не сами по себе — их поведение определяется специальными методами класса, которые называются магическими или дандер-методами (от англ. "double underscore"). Перегрузка операторов позволяет задать логику их работы для ваших собственных объектов.
Это как научить робота готовить кофе: вы не меняете сам кофеварку, а просто программируете новые действия!
Основные дандер-методы для перегрузки операторов
Каждый оператор в Python соответствует определенному дандер-методу. Вот самые популярные:
| Оператор | Дандер-метод | Пример вызова |
|---|---|---|
+ |
__add__ |
obj1 + obj2 |
- |
__sub__ |
obj1 - obj2 |
* |
__mul__ |
obj1 * obj2 |
/ |
__truediv__ |
obj1 / obj2 |
== |
__eq__ |
obj1 == obj2 |
!= |
__ne__ |
obj1 != obj2 |
< |
__lt__ |
obj1 < obj2 |
> |
__gt__ |
obj1 > obj2 |
str() |
__str__ |
print(obj1) |
Пример: Вектора в двумерном пространстве 📐
Допустим, мы хотим создать класс Vector2D, чтобы удобно работать с двумерными векторами.
Реализация базового класса
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
Перегрузка оператора + (__add__)
Теперь научим вектора складываться:
def __add__(self, other):
if isinstance(other, Vector2D):
return Vector2D(self.x + other.x, self.y + other.y)
raise TypeError("Можно складывать только Vector2D!")
Теперь работает:
v1 = Vector2D(2, 3)
v2 = Vector2D(1, 4)
result = v1 + v2 # Vector2D(3, 7)
Перегрузка оператора * (__mul__)
Умножение вектора на число:
def __mul__(self, scalar):
if isinstance(scalar, (int, float)):
return Vector2D(self.x * scalar, self.y * scalar)
raise TypeError("Можно умножать только на число!")
Пример:
v = Vector2D(1, 2)
scaled = v * 3 # Vector2D(3, 6)
Перегрузка оператора == (__eq__)
Сравнение векторов:
def __eq__(self, other):
if isinstance(other, Vector2D):
return self.x == other.x and self.y == other.y
return False
Теперь v1 == v2 вернет True только если координаты совпадают.
Перегрузка __str__ для красивого вывода
def __str__(self):
return f"Vector2D({self.x}, {self.y})"
Теперь print(v1) выведет "Vector2D(2, 3)" вместо <__main__.Vector2D object at 0x...>.
Где ещё применяется перегрузка операторов? 🧠
- Математические объекты: матрицы, комплексные числа.
- Работа с деньгами: класс
Moneyс перегруженными+и-. - Кастомные коллекции: например, переопределение
[](__getitem__). - Контекстные менеджеры:
withиспользует__enter__и__exit__.
Осторожно: подводные камни ⚠️
- Типы операндов. Всегда проверяйте
isinstance()в методах, чтобы избежать ошибок. - Изменяемые объекты. Если ваш класс mutable, убедитесь, что операции вроде
+=(__iadd__) обрабатываются корректно. - Логика операций. Не нарушайте ожидаемое поведение: например,
__eq__должен быть симметричным (a == b⇒b == a).
Чеклист для перегрузки операторов ✅
- Определите, какие операции нужны вашему классу.
- Реализуйте соответствующие дандер-методы.
- Добавьте проверки типов в методах.
- Протестируйте все возможные сценарии использования.
Теперь вы готовы творить магию Python! ✨