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

  Рет қаралды 45,308

selfedu

selfedu

2 жыл бұрын

Курс по Python ООП: stepik.org/a/116336
Делаем сложение объектов с числами и другими экземплярами классов с помощью методов __add__(), __radd__() и __iadd__(). По аналогии выполняются методы: __sub__(), __mul__(), __truediv__()
Инфо-сайт: proproprogs.ru/python_oop
Telegram-канал: t.me/python_selfedu

Пікірлер: 113
@NewSouthMjos
@NewSouthMjos 2 жыл бұрын
Могу добавить, что при реализации __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__)
@minecraftlp6306
@minecraftlp6306 9 ай бұрын
я бы сделал удобочитаемей: def __add__(self, sec): self.__seconds += sec return self
@IdenasTuringTest
@IdenasTuringTest 8 ай бұрын
@@minecraftlp6306 В твоем варианте меняется сам объект. Тогда в примере выше (b = a + 100) получится, что в результате такого "сложения" изменится сам объект "a" и еще оба идентификатора (и "a" и "b") будут ссылаться на один и тот же объект
@user-re1ri9jp3e
@user-re1ri9jp3e 2 жыл бұрын
Просто кладезь знаний 👍 Следующая ступенька, после ООП, паттерны 🙏
@user-ou7fw1sg1r
@user-ou7fw1sg1r 2 жыл бұрын
Идеальный урок.. Моё искреннее почтение Вашему труду... Передача Ваших знаний в массы бесценно...
@user-zt4wx1ks6z
@user-zt4wx1ks6z Жыл бұрын
Сергей, спасибо за уроки!!!
@ravshanmurzaliev4185
@ravshanmurzaliev4185 5 ай бұрын
Очень хорошо объяснили, а то я не мог понять как это работает, после вашего объяснения все стало на свои места, спасибо за ваш труд
@igorratnik2357
@igorratnik2357 Жыл бұрын
Спасибо. Как всегда все доходчиво и понятно!
@user-rn5uk7ep3r
@user-rn5uk7ep3r Жыл бұрын
Очень доступно, спасибо!
@iqabuser6932
@iqabuser6932 7 ай бұрын
Думаю, так будет уже лучше, я вынес в отдельную функцию основу кода и в методах уже вызывал ее и писал знаки 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)
@anvarx1
@anvarx1 Жыл бұрын
Снимаю шляпю и самый низкий поклон до колени !!!
@uladzislawchyrets
@uladzislawchyrets 2 жыл бұрын
Спасибо за уроки
@andredru4278
@andredru4278 3 ай бұрын
Спасибо. Очень интересно.
@VladimirOnokhov
@VladimirOnokhov 9 ай бұрын
спасибо за урок!
@user-et4if5gs8z
@user-et4if5gs8z 2 жыл бұрын
класс! Серёга лучший!
@pphan_
@pphan_ 4 ай бұрын
Вторая неделя изучения ооп!!!!1!1!?1!1?2++1(#-1)2 Если говорить короче,то иду хорошо, спасибо огромное автору за отличное объяснение материала❤
@andredru4278
@andredru4278 3 ай бұрын
Спасибо. Ничего себе, чего можно наворотить.
@jamjam3337
@jamjam3337 Жыл бұрын
спасибо!👏👍
@rukigaki
@rukigaki 7 ай бұрын
При нахождении переменной h в функции get_time нет необходимости искать остаток от деления на 24. Ведь ты сам в инициализаторе сделал так, чтобы секунды не превышали число 86400. А исходя из этого, мы имеем то, что количество секунд в переводе на часы никогда не превысят отметки "24 часа".
@selfedu_rus
@selfedu_rus 7 ай бұрын
Привычка все проверять на всех уровнях.
@TwilightNyann
@TwilightNyann 10 ай бұрын
Это гениально
@dubinin_s
@dubinin_s 2 жыл бұрын
Ураа, домашка)))
@user-uh4bz3lh8l
@user-uh4bz3lh8l Жыл бұрын
Вопрос: что будет если сложить два класса Clock(c1+c2) что вызовется(оба метода определены): с1.__add__(c2) или c2.__rand__(c1). В вашем примере разницы нет, но на практике это могут быть 2 разных класса и от порядка зависит то, какой класс возвращать.
@user-zm5nd9vu7n
@user-zm5nd9vu7n 3 ай бұрын
вроде и понял, но повторить или добавить свое точно не получится, тем кто понимает и применяет такое сразу, завидую)
@user-qd5bg5sw7k
@user-qd5bg5sw7k Жыл бұрын
Чтобы не было дублирования кода - оставшиеся операторы сделать через дескрипторы?
@imadna5810
@imadna5810 18 күн бұрын
Можно тупой вопрос)) Вы говорили, что лучше использовать ссылку на класс, когда его где-то используешь в коде, чтобы не положить программу при замене названия. Можно ли тут использовать cls вместо Clock ?
@user-yn5ox2zu1m
@user-yn5ox2zu1m Жыл бұрын
Для класса Point из предыдущих уроков: class Points: # создание класса def __init__(self, x,y,z): # инициализация self.coords = [x,y,z] def __str__(self): # применяется, если объект класса делают строкой return (f'Координаты точки: '+ f'X = {self.coords[0]} '+ f'Y = {self.coords[1]} '+ f'Z = {self.coords[2]}') def _operate(first,other,action): if isinstance(other, (int, float)): # проверяет тип второго аргумента return Points((eval(f'{first.coords[0]} {action} {other}')), (eval(f'{first.coords[1]} {action} {other}')), (eval(f'{first.coords[2]} {action} {other}'))) elif type(other) == Points: # позволит прибавлять к объекту другой объект класса return Points((eval(f'{first.coords[0]} {action} {other.coords[0]}')), (eval(f'{first.coords[1]} {action} {other.coords[1]}')), (eval(f'{first.coords[2]} {action} {other.coords[2]}'))) else: raise TypeError('второй аргумент должен быть числом или объектом класса') def __add__(self, other): # вызывается, если к объекту класса применить сложение return self._operate(other, '+') def __sub__(self, other): # вызывается, если к объекту класса применить вычитание return self._operate(other, '-') def __mul__(self, other): # вызывается, если к объекту класса применить умножение return self._operate(other, '*') def __truediv__(self, other): # вызывается, если к объекту класса применить деление return self._operate(other, '/') point1 = Points(16,42,12) point2 = Points(1,1,1) point3 = Points(3,3,3) point4 = point1 * point3 - point2 print(point4) ----------------вывод---------------- Координаты точки: X = 47 Y = 125 Z = 35
@user-sb6ot3ry6l
@user-sb6ot3ry6l 6 ай бұрын
Перегрузки операторов в с++ и подобных языках аналогично работают
@user-qj6tk5fw9p
@user-qj6tk5fw9p 11 ай бұрын
Вопрос, почему в методе __add__ мы в место того что бы создавать новый обьект класса Clock не можем просто увеличить поле seconds на передаваемое в параметрах число? ведь в таком случае программа будет работать гораздо быстрее, т.к. на создание нового обьекта класса уходит гораздо больше (по компьютерным меркам) времени?
@vladokko
@vladokko 10 ай бұрын
Насколько я понимаю, именно потому, что мы не всегда хотим при сложении менять исходный экземпляр класса. Например: c2 = c1 + 100 тут нам не нужно, чтобы менялся c1.seconds. А нужно чтобы функция возвращала новый экземпляр и присваивала его переменной c2
@user-el2ll5ws7k
@user-el2ll5ws7k Ай бұрын
Я единственный кто пытается решить задачу с помощью вспомогательного метода класса ? На сколько я понял и ознакомился с темой Дескрипторы созданы не для этих целей , но их кончено же можно и так прописать . На самом то деле они для больше подходят для управления доступом к атрибутам, а не для выполнения арифметических операций. Вот мое решение , сразу скажу не без посторонней помощи , я не гейний ))) сам голову долго ломал как лучше 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'{self.__convert(h)}:{self.__convert(m)}:{self.__convert(s)}' @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)
@user-kt4yy5cf5e
@user-kt4yy5cf5e 2 жыл бұрын
Было бы элегантней написать sc = other.seconds if isinstance(other, Click) else other)
@user-dw6lj2po9r
@user-dw6lj2po9r 2 жыл бұрын
Подскажите пожалуйста зачем нужен return self в конце метода __iadd__. буду благодарен
@selfedu_rus
@selfedu_rus 2 жыл бұрын
Чтобы результат можно было присвоить какой-либо другой переменной (ссылку на объект). Если этого не требуется, то можно не возвращать (вроде бы).
@ibrahimoglu
@ibrahimoglu 2 жыл бұрын
👍
@demobunt
@demobunt 2 жыл бұрын
В проверке isinstance значения bool проходят как int. Возможно корректнее через type?
@selfedu_rus
@selfedu_rus 2 жыл бұрын
да, если нужно четкое сравнение на типы, то конечно, type
@alexandreabramtsev9160
@alexandreabramtsev9160 Жыл бұрын
поправьте меня, если я не до конца правильно понимаю. Мне кажется что 5:08 минуте метод __get_formatted правильнее сделать статическим методом а не методом класса потому что он используется в методе экземпляра класса (в объекте). Понятно что будет работать и так и так, но все же.... ?
@fWhyJKE
@fWhyJKE Жыл бұрын
Ебать, хорош, мужик. Также подумал. Хорошо что не один такой. Вот так прописал: @staticmethod def ver_sec(x): if not isinstance(x, int): raise TypeError('need int')
@user-qv8gn1yq8t
@user-qv8gn1yq8t 11 ай бұрын
А не проще вместо __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__ сделали?
@BritScientist
@BritScientist 6 ай бұрын
Вроде бы принято при неподходящем типе операндов в арифметических методах не вызывать исключение, а возвращать константу NotImplemented. Это позволяет попытаться обратиться к соответствующему методу второго операнда прежде чем выкидывать ошибку.
@J1mDGriz
@J1mDGriz Жыл бұрын
правильно я понимаю, что метод __add__ он более общий по сравнению с radd и iadd?
@Antinormanisto
@Antinormanisto 2 ай бұрын
Насчёт домашки, можно либо сделать класс метод который считывает other и его уже превращает в цифарки и в ариф. методах делать self.seconds + func(other), либо сделать декоратор, и обернуть ариф. методы Собственно вот мой второй путь from functools import wraps 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 return f"{h:02}:{m:02}:{s:02}" def __calculate(func): @wraps(func) def wrapper(self, other): if not isinstance(other, (int, Clock)): raise TypeError("Одумайся грешник") if isinstance(other, Clock): other = other.seconds return Clock(func(self.seconds, other)) return wrapper @__calculate def __add__(self, other): return self + other def __radd__(self, other): return self + other @__calculate def __sub__(self, other): return self - other @__calculate def __mul__(self, other): return self * other @__calculate def __floordiv__(self, other): return self // other
@user-cm1ri1sn2u
@user-cm1ri1sn2u Жыл бұрын
Сергей, а почему при использовании .rjust(2, 0) вы говорите, что нолик добавляется справа? Ведь он добавляется слева от цифр. Можно конечно предположить, что цифра смотрит на нас "лицом" и то, что мы воспринимаем как слева от неё, это на самом деле справа, но в таком случае при объяснении __add__(self, other) вы объясняете, что other это то, что стоит права от c1
@selfedu_rus
@selfedu_rus Жыл бұрын
да я просто оговорился! Конечно, слева! ))
@user-cm1ri1sn2u
@user-cm1ri1sn2u Жыл бұрын
@@selfedu_rus но ведь и метод почему-то начинается на r, а тот, что добавляет символы справа на l, какая-то путаница. А ещё подскажите, планируете ли вы делать на stepik курсы по джанго, базам данных и всему тому, что необходимо для бэкенда? Ролики на эти темы у вас на канале есть, но без практических задач сухая теория совсем не усваивается
@selfedu_rus
@selfedu_rus Жыл бұрын
думал про Django, но на Stepik сложно сделать хороший курс по нему, т.к. это ж фреймворк. Это останавливает.
@user-cm1ri1sn2u
@user-cm1ri1sn2u Жыл бұрын
@@selfedu_rus надеюсь, что решение будет найдено. Низкий вам поклон и благодарность за то, что вы для всех нас делаете, учиться у вас - одно удовольствие!
@ravshanmurzaliev4185
@ravshanmurzaliev4185 5 ай бұрын
​@@selfedu_rus Я думаю если найдете решение и сделайте курс платным будет пользоваться спросом так как нормального курса по джанго нет сейчас
@olga_zhu
@olga_zhu Жыл бұрын
Добрый день. Сориентируйте, пожалуйста, почему мы присваиваем функции get_formatted уровень класса @classmethod? В нем же не используются атрибуты класса, тот же __DAY. Заранее благодарна!
@selfedu_rus
@selfedu_rus Жыл бұрын
да, здесь вполне можно прописать статик, все верно!
@olga_zhu
@olga_zhu Жыл бұрын
Благодарю за столь оперативный ответ! У меня появился ещё вопрос, если позволите. В коде мы в явном виде прописываем класс Clock, когда нам надо создавать экземпляры объектов для сложения в ф-ии __add__ и когда делаем проверку на принадлежность other к классу. Правильно ли я понимаю, что в данном случае мы никоим образом не можем уйти от прямого обращения к классу, заменив на cls или self, как делали в других уроках? Ведь если наименование класса Clock изменится, то потребуется менять наименование во всех местах, где было прямое обращение. Надеюсь, мой вопрос понятен :)
@olga_zhu
@olga_zhu Жыл бұрын
Нашла ответ на свой вопрос у Евгения ниже) Ещё раз спасибо за Вашу подачу материала!
@user-jh9vd1xo4g
@user-jh9vd1xo4g Жыл бұрын
@selfedu Серёга молодец конечно. Но ты не сказал зачем нужны эти методы на практике.
@backsoul44
@backsoul44 6 ай бұрын
почему "Магические"?
@user-fs9ou5lx9l
@user-fs9ou5lx9l 2 жыл бұрын
Не понятно как происходит вызов метода radd. Если я выполняю с1 + 100, происходит вызов с1.__add__(100). Вызывая 100 + с1, я ожидаю вызов 100.__add__(c1), т. Е метод класса int. Как интерпретатор понимает, что нужно вызвать именно radd нашего класса?
@selfedu_rus
@selfedu_rus 2 жыл бұрын
здесь сам интерпретатор уже "соображает", что нужно вызвать именно radd, т.к. такой метод определен в c1
@ask971
@ask971 2 жыл бұрын
А можно подсказку по том, как без дублирования кода засунуть все арифметические операции в класс, ведь по сути код для маг метода __add__ отличается от __sub__, __mul__, __truediv__ только названием метода и конкретной операцией. Через каррирование загнав все маг методы в словарь с соответствующим оператором, или видео урок про дескрипторы как раз здесь и можно применить, или я вовсе перемудрил и решение куда проще? Проверки на int, Clock тоже можно было засунуть в отдельный @classmetod для соблюдения "dry" это бы упростило читабельность и громоздкость кода? Заранее спасибо..
@user-iy6vk4pn1j
@user-iy6vk4pn1j Жыл бұрын
Я думаю словарь нужно составить 'операция':'знак операции' и использовать eval()
@user-jz8ik6ck8o
@user-jz8ik6ck8o Жыл бұрын
class Desc: def __init__(self): self.opdct={'add':'+','sub':'-','mul':'*','truediv':'/'} def __set_name__(self,owner,name): name=name.strip('_') self.prefix=name[0] if name.startswith(('i','r')) else None self.name=name[1:] if self.prefix else name def __get__(self,obj,owner): def wrapp(other): if type(other) in (int,float): n1,n2=obj.num,other else: n1,n2=obj.num,other.num if not self.prefix: return owner(self.op(self.opdct[self.name],n1,n2)) if self.prefix=='r': return owner(self.op(self.opdct[self.name],n2,n1)) if self.prefix=='i': setattr(obj,'num',self.op(self.opdct[self.name],n1,n2)) return obj return wrapp @staticmethod def op(opsign,n1,n2): return eval(f'{n1}{opsign}{n2}') class A: __add__=Desc() __sub__=Desc() __mul__=Desc() __truediv__=Desc() __radd__=Desc() __rsub__=Desc() __rmul__=Desc() __rtruediv__=Desc() __iadd__=Desc() __isub__=Desc() __imul__=Desc() __itruediv__=Desc() def __init__(self,num): но это все самая первая проба....развитие и улучшение в моих решениях на степике суть метода использование non-data дескрипторов и замыканий в _get_ типовая конструкция такая def __get__(self,object,owner): def inner(other): return ... return inner а для работы с методами такая еще конструкция return owner(getattr(object.param,self.name)(other.param))-если нам например нужно получить результат арифметической операции над объектом как новый объект с параметром -результатом операции над 2 объектами КОРОЧЕ ПАСАНЫ ,,,,Я ЭТИ ВАШИ МАГМЕТОДЫ НА ДЕСКРИПТОРЕ ВЕРТЕЛ КАК ХОТЕЛ))))))
@ilyazheprog
@ilyazheprog Жыл бұрын
Меня месяц тревожит вопрос, проиллюстрирую на примере из видео: c1 = Clock(1000) c1 = c1 + 100 Как сделать, чтобы работало и c1 = 100 + c1 ? Заранее спасибо)
@selfedu_rus
@selfedu_rus Жыл бұрын
__radd__
@interface5900
@interface5900 2 жыл бұрын
Вроде неплохо получилось def universal_operation(self, other, operation: str, for_myself: bool): if not isinstance(other, (int, Clock)): raise ArithmeticError(f'unsupported operand type(s) for +: {type(self)} and {type(other)}') sc = other if isinstance(other, Clock): sc = other.seconds if not for_myself: if operation == '+': answer = Clock(self.seconds + sc) elif operation == '-': answer = Clock(self.seconds - sc) return answer else: if operation == '+': self.seconds = (self.seconds + sc) % self.__DAY elif operation == '-': self.seconds = (self.seconds - sc) % self.__DAY return self
@user-qj6tk5fw9p
@user-qj6tk5fw9p 11 ай бұрын
Да, и я попровал в методе __add__ не создавать новый обьект класса, а изменять поле self.seconds и возвращать ссылку на текущий обьект класса. множественное сложение, и все другие виды сложений так же прекрасно работают. И программа соответственно должна работать быстрее, получается одни плюсы
@selfedu_rus
@selfedu_rus 11 ай бұрын
так у вас и значения в объектах, участвующих в сложениях будут тогда меняться
@user-qj6tk5fw9p
@user-qj6tk5fw9p 11 ай бұрын
@@selfedu_rus ну, вот сейчас посмотрел, не изменились значения в обьектах участвующих в сложении, все работает так как и должно
@selfedu_rus
@selfedu_rus 11 ай бұрын
@@user-qj6tk5fw9p вы в add делаете так: return self.seconds + other тогда да, в самом объекте ничего меняться не будет. Это мой ляп. Но объект все же нужен (в общем случае), т.к. хорошо, что здесь числа складываются, а если бы мы комплексные числа складывали? Тогда без объекта не работало бы.
@user-qj6tk5fw9p
@user-qj6tk5fw9p 11 ай бұрын
@@selfedu_rus Понял, спасибо)
@sladge17
@sladge17 2 жыл бұрын
Можно ли в iadd не делать return self, ведь на уже изменили значение атрибута в экземпляре, или будет ошибка?
@selfedu_rus
@selfedu_rus 2 жыл бұрын
нужно, т.к. там идет присваивание результата операнду слева от оператора +=
@sladge17
@sladge17 2 жыл бұрын
Спасибо за ответ
@skamikus
@skamikus 2 жыл бұрын
@@selfedu_rus вряд-ли увижу ответ, но попытаюсь) В __radd__ мы получаем self и изменяя экземпляр через него, по сути методом и запишем значение, или я не прав? self ведь получается берет как раз что нам и нужно...
@skamikus
@skamikus 2 жыл бұрын
Все таки проверил и даже вроде осознал return нужен! ))
@romankucheruk8974
@romankucheruk8974 2 жыл бұрын
Спасибо крутое ДЗ: class Clock: __DAY = 86400 def __init__(self,seconds:int): if not isinstance(seconds,(int,float)): raise TypeError("Must be int or flot") 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"{self.__get_formatted(h)}:{self.__get_formatted(m)}:{self.__get_formatted(s)}" @classmethod def __get_formatted(cls,x): return str(x).rjust(2, "0") def process(func): def inner(self, other): if not isinstance(other, (int, Clock)): raise ArithmeticError(" Right operant must be int") sc = other if isinstance(other, Clock): sc = other.seconds return Clock(func(self.seconds, sc)) return inner @process def __add__(self, other): return self + other def __radd__(self, other): return self + other @process def __sub__(self, other): return self - other @process def __mul__(self, other): return self * other @process def __truediv__(self, other): return self / other c1 = Clock(1000) c2 = Clock(2000) print(c1.get_time()) print(c2.get_time()) c3 = c1 + c2 print(c3.get_time()) c4 = c3 - c2 print(c4.get_time()) c5 = c2 / c1 print(c5.get_time())
@user-jz8ik6ck8o
@user-jz8ik6ck8o Жыл бұрын
🤣все с точностью донаоборот....не прописывать каждую функцию и декорировать ее,а создать дескриптор который будет описывать всю шоблу этих функций)))))....просто поэкспериментируй с конструкцией __get__(): def inner(other): return ..... return inner
@cosmoboyplays4085
@cosmoboyplays4085 11 ай бұрын
во, твой вариант мне прям понравился
@BritScientist
@BritScientist 6 ай бұрын
Возможности f-строк в Python позволяют обойтись без метода __get_formatted() вот таким образом: {self.h:>02}
@J1mDGriz
@J1mDGriz Жыл бұрын
почему на 23 строчке нельзя было написать if isinstance(other, Clock): other = other.seconds return Clock(self.seconds + other) без введения доп переменной
@DuhaxD
@DuhaxD 2 жыл бұрын
Кажется, что было бы правильнее в методе __add__ поступить также как и с __iadd__. Так, в методе __add__ нам не придется создавать новый экземпляр (мы можем просто увеличить атрибут seconds, а затем вернуть self). Или мне не правильно кажется?) def __add__(self, other): if not isinstance(other, (int, Clock)): raise ArithmeticError("Adding number must be int") sc = other if isinstance(other, Clock): sc = other.seconds self.seconds += sc return self # return Clock(self.seconds + sc)
@user-cm9mn3wb2t
@user-cm9mn3wb2t 2 жыл бұрын
А Вы прогоните свой вариант на объектах класса например p1 = Class(100), p2 = Class(200) и p3 = p1 + p2, а потом выведите что находится в p1, p2, p3 и поймете почему именно у __iadd__ другая реализация
@user-ph7nw6tr9b
@user-ph7nw6tr9b 24 күн бұрын
При попытке реализовать def __rsub__(self, other): return self - other он вычитает из объекта число, хотя хотелось бы наоборот. Как?
@user-ph7nw6tr9b
@user-ph7nw6tr9b 21 күн бұрын
Решил проблему простой заменой знака результата. Это нормально, или как-то ещё делают?
@user-cb1kz3mv7j
@user-cb1kz3mv7j 3 ай бұрын
А зачем нужна __get_formated() функция? Проще же так: return f'{h:02}:{m:02}:{s:02}'. Ладно, буду считать, что это тренировка использования декоратора @classmethod
@Sergiypsm
@Sergiypsm 2 жыл бұрын
Решение задачи поставленной в конце видео: использовать менеджер контекста width? Или это неправильный путь?
@selfedu_rus
@selfedu_rus 2 жыл бұрын
не совсем понятно для чего with?
@Sergiypsm
@Sergiypsm 2 жыл бұрын
@@selfedu_rus да, глупость я сморозил. Скорее, опять нужна какая-то магия.
@Sergiypsm
@Sergiypsm 2 жыл бұрын
Вроде получилось colab.research.google.com/drive/1M4Cdv82HeVBcQE-kn-zTRzjIWFNbrjpt?usp=sharing
@user-jz8ik6ck8o
@user-jz8ik6ck8o Жыл бұрын
попытался превратить магию методов в вуду дескрипторов и замыканий class Desc: def __init__(self): self.opdct={'add':'+','sub':'-','mul':'*','truediv':'/'} def __set_name__(self,owner,name): name=name.strip('_') self.prefix=name[0] if name.startswith(('i','r')) else None self.name=name[1:] if self.prefix else name def __get__(self,obj,owner): def wrapp(other): if type(other) in (int,float): n1,n2=obj.num,other else: n1,n2=obj.num,other.num if not self.prefix: return owner(self.op(self.opdct[self.name],n1,n2)) if self.prefix=='r': return owner(self.op(self.opdct[self.name],n2,n1)) if self.prefix=='i': setattr(obj,'num',self.op(self.opdct[self.name],n1,n2)) return obj return wrapp @staticmethod def op(opsign,n1,n2): return eval(f'{n1}{opsign}{n2}') class A: __add__=Desc() __sub__=Desc() __mul__=Desc() __truediv__=Desc() __radd__=Desc() __rsub__=Desc() __rmul__=Desc() __rtruediv__=Desc() __iadd__=Desc() __isub__=Desc() __imul__=Desc() __itruediv__=Desc() def __init__(self,num): но это все самая первая проба....развитие и улучшение в моих решениях на степике суть метода использование non-data дескрипторов и замыканий в __get__ типовая конструкция такая def __get__(self,object,owner): def inner(other): return ... return inner а для работы с методами такая еще конструкция return owner(getattr(object.param,self.name)(other.param))-если нам например нужно получить результат арифметической операции над объектом как новый объект с параметром -результатом операции над 2 объектами КОРОЧЕ ПАСАНЫ ,,,,Я ЭТИ ВАШИ МАГМЕТОДЫ НА ДЕСКРИПТОРЕ ВЕРТЕЛ КАК ХОТЕЛ))))))
@eazy8537
@eazy8537 11 ай бұрын
А зачем часы ещё делить по остатку на 24, если в принципе их не может быть больше 24, благодаря делению секунд на __DAY, или я чего-то не понимаю? И почему мы используем метод класса вместо статик метода, если мы не работаем с атрибутами класса?
@selfedu_rus
@selfedu_rus 11 ай бұрын
на 24 делю для надежности, чтобы точно не было больше (привычка везде делать "защиту от дурака"), а метод да, здесь вполне и статик подойдет.
@nomadicus77
@nomadicus77 Жыл бұрын
Ех зная это можно было бы задание в 3.3 последние легче сделать)))
@return_1101
@return_1101 2 жыл бұрын
У меня освободилось кучу времени, и прохожу курс в степик. (Но я очень далеко... На 3.7... ((() Этот курс будет там еще долго? Уважаю ваш труд. Вы гений.
@selfedu_rus
@selfedu_rus 2 жыл бұрын
Спасибо! Да, я надеюсь, курс надолго )
@user-dw6lj2po9r
@user-dw6lj2po9r 2 жыл бұрын
@@selfedu_rus у вас есть курс на степике?
@selfedu_rus
@selfedu_rus 2 жыл бұрын
@@user-dw6lj2po9r по ООП нет
@user-zi3lb8qu3s
@user-zi3lb8qu3s 2 жыл бұрын
@@user-dw6lj2po9r есть))
@Konstantin_Stalnov
@Konstantin_Stalnov Жыл бұрын
Почему вначале при сложении мы создаём новый Экземпляр Класса, а потом (+=) мы просто меняем значение Атрибута Экземпляра Класса. Почему в первом случае мы не можем поменять? Зачем нам создавать новый Экземпляр Класса.
@user-ym4uf8bj6f
@user-ym4uf8bj6f 11 ай бұрын
Дякую за відео, але не дуже зрозумів тут 12:02, що означає sc = other.seconds
@selfedu_rus
@selfedu_rus 11 ай бұрын
Там при сложении операнд справа может быть как число, так и объект Clock. Отсюда и появляется проверка в add.
@user-rl7dv8qn7z
@user-rl7dv8qn7z 2 жыл бұрын
Не понятно, если эти методы из коробки идут, то зачем в них еще столько кода писать, почему они сразу в две или одну строчку не идут? или я не про то? )
@selfedu_rus
@selfedu_rus 2 жыл бұрын
не про то, можно их вообще не переопределять, если не нужно, в противном случае прописываем свой алгоритм, а сколько строчек кода - это зависит от задачи
@user-gs3dd2le1e
@user-gs3dd2le1e 2 жыл бұрын
зачем было городить еще и __get_formatted() ? можно было все уместить в f-строку
@johnmazepa
@johnmazepa 11 ай бұрын
а зачем мы в качестве возвращаемого значения метода __add__ устанавливаем НОВЫЙ объект класса Clock с увеличенным количеством секунд: return Clock(self.seconds + other) вместо того, чтобы просто увеличить значение для текущего объекта: return self.seconds + other ?
@johnmazepa
@johnmazepa 11 ай бұрын
или это просто демонстрация того, как можно манипулировать данными, а нам на практике уже нужно будет действовать на своё усмотрение в зависимости от ситуации?
@selfedu_rus
@selfedu_rus 11 ай бұрын
@@johnmazepa если нужно несколько слагаемых, например: a+b+c+d
@ChilikovAleksandr
@ChilikovAleksandr 11 ай бұрын
В данной реализации вернется количество секунд, а не экземпляр класса Clock. Если требуется изменить атрибут конкретного класса и вернуть экземпляр этого же класса (без создания нового), предлагаю примерно такой вариант: def __add__(self, other): if not isinstance(other, (int, Clock)): raise ArithmeticError("Атрибут должен быть целым числом (int) и объектом класса Clock") if isinstance(other, int): self._seconds += other if isinstance(other, Clock): self._seconds += other._seconds return self
@IdenasTuringTest
@IdenasTuringTest 8 ай бұрын
Очень советую избегать этих магических методов (именно этих 4-х). Лучше сделайте отдельные обычные методы add(), sub() или назовите какими-нибудь increase(), decrease(). И в методах просто соответственно увеличивайте или уменьшайте свойство seconds. Если же вы все-таки решили добавить логику сложения объектов с этими маг-методами, то обязательно протестируйте результат на всех возможных вариантах: объект справа от плюса, слева от плюса, складываются два объекта и результат присваивается третьему. И обязательно каждый раз проверяйте все свойства (в примере из видео это одно свойство seconds) всех объектов. А вот если вы создадите дочерний класс от этого, гемор вам обеспечен 😁
@konstantinpluzhnikov4862
@konstantinpluzhnikov4862 Жыл бұрын
не думай о секундах свысока.
@SASka-ct7zj
@SASka-ct7zj 2 жыл бұрын
Как понять незначищий ноль справа , а потом говорите если 1 2 или то будет 0 1 0 2 и тд., где логика? Там помойму число больше нуля вправа едет а нули влево
@kazybekkydyrbai8632
@kazybekkydyrbai8632 Жыл бұрын
Да ладно к словам придираться, главное суть же объяснили и код правильно работает. rjust делает выравнивание с право(right).
@user-pi1ez7ju5x
@user-pi1ez7ju5x 6 ай бұрын
Материал и подача хорошие, но английский плох. Рекомендую подучить произношение слов, которые используются в программировании. Неправильное произношение вызывает недоумение у незнающих людей. Ещё было бы полезно объяснять полное название методов, например mul - multiply(умножать). В данном видео метод __add__ читается как "эд" (добавить)
@nothman
@nothman 2 күн бұрын
Не мог проще пример взять?!!!! Кучу воды наговорил, пока до маг. метода добрался.
КАРМАНЧИК 2 СЕЗОН 6 СЕРИЯ
21:57
Inter Production
Рет қаралды 506 М.
How many pencils can hold me up?
00:40
A4
Рет қаралды 19 МЛН
Как быстро замутить ЭлектроСамокат
00:59
ЖЕЛЕЗНЫЙ КОРОЛЬ
Рет қаралды 12 МЛН
18 Фишек Python о которых мало кто говорит
14:13
Магические методы в python. Dunder методы
1:00:45
КАРМАНЧИК 2 СЕЗОН 6 СЕРИЯ
21:57
Inter Production
Рет қаралды 506 М.