Знакомьтесь с основными магическими методами:
• add() – сложение
• sub() – вычитание
• mul() – умножение
• truediv() – обычное деление
• floordiv() – целочисленное деление
• mod() – остаток от деления
Лучше один раз увидеть, чем 100500 раз прочитать! 👀 Внимание - очень много букв😁😁😁
Возьмем класс для работы со временем. Время храним в секундах (макс. 86400 - секунд в сутках):
class Clock:
__DAY = 86400 # секунд в сутках
def __init__(self, seconds: int):
if not isinstance(seconds, int):
raise TypeError("Секунды должны быть целым числом")
self.seconds = seconds % self.__DAY
def get_time(self):
s = self.seconds % 60 # секунды
m = (self.seconds // 60) % 60 # минуты
h = (self.seconds // 3600) % 24 # часы
return f"{h:02}:{m:02}:{s:02}"
Добавляем сложение ➕
Сначала научим складывать с числами:
def __add__(self, other): #
if not isinstance(other, int):
raise ArithmeticError("Правый операнд должен быть типом int")
return Clock(self.seconds + other)
Теперь работает:
с1 = Clock(1000)
с1 = с1 + 100
print(с1.get_time()) # 00:18:20
Усложняем - складываем два объекта Clock:
def __add__(self, other):
if not isinstance(other, (int, Clock)):
raise ArithmeticError("Правый операнд должен быть типом int или объектом Clock")
sc = other if isinstance(other, int) else other.seconds
return Clock(self.seconds + sc)
Теперь:
c1 = Clock(1000)
c2 = Clock(100)
c3 = c1 + c2
print(c3.get_time()) # # 00:18:20
Закончили? Неа! ❌
Не работает: c1 = 100 + c1 # Ошибка!
Добавляем обратное сложение 🔄
def __radd__(self, other):
return self + other # перекидывает в __add__(self, other) .
Теперь 100 + c1 работает. Почему кидает в add? Честно - я не до конца понял 😅
c1 = Clock(1000)
c1 = 100 + c1
print(c1.get_time()) # 00:18:20
Но метод выше можно еще реализовывать например таким способом, тут всraddее:
def __radd__(self, other):
return self.__add__(other)
Ну теперь уж точно всё, подумали вы. Нет😂😂 все еще не работает такой стиль c1 += c2🙈
Точнее работает, но не так. как хотелось бы. Мы пока что возвращаем(создаем) новый объект, а здесь новый эзкемпляр создавать не надо. Надо просто изменять на месте, для этого напишем так.
Изменяем объект на месте (не iadd новый)
def __iadd__(self, other):
print("__iadd__")
if not isinstance(other, (int, Clock)):
raise ArithmeticError("Правый операнд должен быть типом int или объектом Clock")
sc = other if isinstance(other, int) else other.seconds
self.seconds += sc
return self # возвращаем тот же объект!
Теперь c1 += c2 изменяет сам c1 🎯
Важный нюанс:
🟡 + создает новый объект
🟡 += изменяет существующий
Для изменяемых классов (как списки) можно всегда возвращать старый объект.
Другие методы делаются абсолютно аналогично.
Итог:
Теперь вы знаете, как работают операции в int, float, str! Все ошибки, которые вы видели - это как раз проверки в этих dunder методах.
Как вам такие "магические" методы? 👇
🔥 — Огонь, приму на вооружение!
🤔 — Знал, но освежил память.
🐍 — Здесь притаился питон.raddто объясниaddму
__radd__ вызывает __add__ в первом варианте реализации этого метода? Жду в комментах! 👇