#14 Магические методы __add__, __sub__, __mul__, __truediv__ | ООП Python

preview_player
Показать описание

Делаем сложение объектов с числами и другими экземплярами классов с помощью методов __add__(), __radd__() и __iadd__(). По аналогии выполняются методы: __sub__(), __mul__(), __truediv__()

Рекомендации по теме
Комментарии
Автор

Могу добавить, что при реализации __add__ лучше обращаться к своему классу через self.__class__, а не напрямую через название Clock. Потому что названия классов имеют свойство меняться, и ничего внутри класса ломаться при этом не должно.


class Clock():
def __init__(self, seconds) -> None:
self.__seconds = seconds

def __add__(self, other):
return self.__class__(self.__seconds + other)

a = Clock(100)
b = a + 100
print(b.__dict__)

NewSouthMjos
Автор

Просто кладезь знаний 👍
Следующая ступенька, после ООП, паттерны 🙏

rerijpe
Автор

Идеальный урок.. Моё искреннее почтение Вашему труду... Передача Ваших знаний в массы бесценно...

oufwsgr
Автор

Очень хорошо объяснили, а то я не мог понять как это работает, после вашего объяснения все стало на свои места, спасибо за ваш труд

ravshanmurzaliev
Автор

Спасибо. Как всегда все доходчиво и понятно!

igorratnik
Автор

Снимаю шляпю и самый низкий поклон до колени !!!

anvarx
Автор

Я единственный кто пытается решить задачу с помощью вспомогательного метода класса ? На сколько я понял и ознакомился с темой Дескрипторы созданы не для этих целей, но их кончено же можно и так прописать . На самом то деле они для больше подходят для управления доступом к атрибутам, а не для выполнения арифметических операций. Вот мое решение, сразу скажу не без посторонней помощи, я не гейний ))) сам голову долго ломал как лучше


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

@staticmethod
def __convert(x):
return str(x).rjust(2, '0')

def _operate_time(self, other, operator):
if not isinstance(other, int):
raise TypeError('Операция допустима только с целыми числами')
new_seconds = operator(self.seconds, other) % self.__DAY
return Clock(new_seconds)

def __add__(self, other):
return self._operate_time(other, lambda x, y: x + y)

def __sub__(self, other):
return self._operate_time(other, lambda x, y: x - y)

def __mul__(self, other):
return self._operate_time(other, lambda x, y: x * y)

def __truediv__(self, other):
if other == 0:
raise ZeroDivisionError("Нельзя делить на ноль")
return self._operate_time(other, lambda x, y: int(x / y))

def __floordiv__(self, other):
if other == 0:
raise ZeroDivisionError("Нельзя делить на ноль")
return self._operate_time(other, lambda x, y: x // y)

def __mod__(self, other):
if other == 0:
raise ZeroDivisionError("Нельзя брать остаток от деления на ноль")
return self._operate_time(other, lambda x, y: x % y)


def __radd__(self, other):
return self.__add__(other)

def __rsub__(self, other):
if not isinstance(other, int):
raise TypeError('Можно отнимать только от целого числа')
return Clock((other - self.seconds) % self.__DAY)

def __rmul__(self, other):
return self.__mul__(other)

elllwsk
Автор

Думаю, так будет уже лучше, я вынес в отдельную функцию основу кода и в методах уже вызывал ее и писал знаки

def met(self, other):
if not isinstance(other, (int, Clock)):
raise ArithmeticError("Допускаешь ошибку")
sc = other
if isinstance(other, Clock):
sc = other.seconds
return sc

def __sub__(self, other):
sc = self.met(other)
return Clock(self.seconds - sc)

def __mul__(self, other):
sc = self.met(other)
return Clock(self.seconds * sc)

def __floordiv__(self, other):
sc = self.met(other)
return Clock(self.seconds // sc)

sunonphyse
Автор

Вторая неделя изучения ооп!!!!1!1!?1!1?2++1(#-1)2
Если говорить короче, то иду хорошо, спасибо огромное автору за отличное объяснение материала❤

pphan_
Автор

Спасибо. Ничего себе, чего можно наворотить.

andredru
Автор

При нахождении переменной h в функции get_time нет необходимости искать остаток от деления на 24. Ведь ты сам в инициализаторе сделал так, чтобы секунды не превышали число 86400. А исходя из этого, мы имеем то, что количество секунд в переводе на часы никогда не превысят отметки "24 часа".

rukigaki
Автор

вроде и понял, но повторить или добавить свое точно не получится, тем кто понимает и применяет такое сразу, завидую)

zmndvun
Автор

Было бы элегантней написать sc = other.seconds if isinstance(other, Click) else other)

ktyycfe
Автор

Перегрузки операторов в с++ и подобных языках аналогично работают

sbotryl
Автор

Вопрос: что будет если сложить два класса Clock(c1+c2) что вызовется(оба метода определены): с1.__add__(c2) или c2.__rand__(c1). В вашем примере разницы нет, но на практике это могут быть 2 разных класса и от порядка зависит то, какой класс возвращать.

uhbzlhl
Автор

А не проще вместо __get_formatted сделать так:
def get_time(self):
"""Получить текущее время."""
s = self.seconds % 60
m = self.seconds % 3600 // 60
h = self.seconds // 3600
return f'{h:02d}:{m:02d}:{s:02d}'

И "h" зачем "% 24", когда это уже в __init__ сделали?

qvgnyqt
Автор

Чтобы не было дублирования кода - оставшиеся операторы сделать через дескрипторы?

qdbgswk
Автор

Вроде бы принято при неподходящем типе операндов в арифметических методах не вызывать исключение, а возвращать константу NotImplemented. Это позволяет попытаться обратиться к соответствующему методу второго операнда прежде чем выкидывать ошибку.

BritScientist
Автор

Вопрос, почему в методе __add__ мы в место того что бы создавать новый обьект класса Clock не можем просто увеличить поле seconds на передаваемое в параметрах число? ведь в таком случае программа будет работать гораздо быстрее, т.к. на создание нового обьекта класса уходит гораздо больше (по компьютерным меркам) времени?

qjtkfwp
Автор

Да, и я попровал в методе __add__ не создавать новый обьект класса, а изменять поле self.seconds и возвращать ссылку на текущий обьект класса. множественное сложение, и все другие виды сложений так же прекрасно работают. И программа соответственно должна работать быстрее, получается одни плюсы

qjtkfwp