Просто кладезь знаний 👍 Следующая ступенька, после ООП, паттерны 🙏
@NewSouthMjos2 жыл бұрын
Могу добавить, что при реализации __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 Жыл бұрын
я бы сделал удобочитаемей: def __add__(self, sec): self.__seconds += sec return self
@IdenasTuringTest Жыл бұрын
@@minecraftlp6306 В твоем варианте меняется сам объект. Тогда в примере выше (b = a + 100) получится, что в результате такого "сложения" изменится сам объект "a" и еще оба идентификатора (и "a" и "b") будут ссылаться на один и тот же объект
@андрейхоменко-и5я2 жыл бұрын
Идеальный урок.. Моё искреннее почтение Вашему труду... Передача Ваших знаний в массы бесценно...
@ravshanmurzaliev418511 ай бұрын
Очень хорошо объяснили, а то я не мог понять как это работает, после вашего объяснения все стало на свои места, спасибо за ваш труд
@keribirinto Жыл бұрын
Думаю, так будет уже лучше, я вынес в отдельную функцию основу кода и в методах уже вызывал ее и писал знаки 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)
@andredru42788 ай бұрын
Спасибо. Ничего себе, чего можно наворотить.
@pphan_10 ай бұрын
Вторая неделя изучения ооп!!!!1!1!?1!1?2++1(#-1)2 Если говорить короче,то иду хорошо, спасибо огромное автору за отличное объяснение материала❤
@rukigaki Жыл бұрын
При нахождении переменной h в функции get_time нет необходимости искать остаток от деления на 24. Ведь ты сам в инициализаторе сделал так, чтобы секунды не превышали число 86400. А исходя из этого, мы имеем то, что количество секунд в переводе на часы никогда не превысят отметки "24 часа".
@selfedu_rus Жыл бұрын
Привычка все проверять на всех уровнях.
@ДмитрийАлексеев-ц5щ2 жыл бұрын
Сергей, спасибо за уроки!!!
@andredru42788 ай бұрын
Спасибо. Очень интересно.
@igorratnik2357 Жыл бұрын
Спасибо. Как всегда все доходчиво и понятно!
@РайнГослинг-р4к6 ай бұрын
Я единственный кто пытается решить задачу с помощью вспомогательного метода класса ? На сколько я понял и ознакомился с темой Дескрипторы созданы не для этих целей , но их кончено же можно и так прописать . На самом то деле они для больше подходят для управления доступом к атрибутам, а не для выполнения арифметических операций. Вот мое решение , сразу скажу не без посторонней помощи , я не гейний ))) сам голову долго ломал как лучше 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)
@anvarx12 жыл бұрын
Снимаю шляпю и самый низкий поклон до колени !!!
@ДимычДимон-г3ю11 ай бұрын
Перегрузки операторов в с++ и подобных языках аналогично работают
@МамонтовОлег-в9о2 жыл бұрын
класс! Серёга лучший!
@Блинчик-н4о Жыл бұрын
Вопрос: что будет если сложить два класса Clock(c1+c2) что вызовется(оба метода определены): с1.__add__(c2) или c2.__rand__(c1). В вашем примере разницы нет, но на практике это могут быть 2 разных класса и от порядка зависит то, какой класс возвращать.
@VladimirOnokhov Жыл бұрын
спасибо за урок!
@BritScientist Жыл бұрын
Вроде бы принято при неподходящем типе операндов в арифметических методах не вызывать исключение, а возвращать константу NotImplemented. Это позволяет попытаться обратиться к соответствующему методу второго операнда прежде чем выкидывать ошибку.
@TwilightNyann Жыл бұрын
Это гениально
@ЗахарСавчин-ж5п Жыл бұрын
Очень доступно, спасибо!
@РустамРаджабов-ц3м8 ай бұрын
вроде и понял, но повторить или добавить свое точно не получится, тем кто понимает и применяет такое сразу, завидую)
@БогданСыроватский-б6ж2 жыл бұрын
Для класса 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
@exist_k2748Ай бұрын
Здравствуйте. Я понимаю, что в методе __add__ новый экземпляр создаётся для того, чтобы можно было присвоить сложению другую переменную. Но, если мы выполним c1 = c1 + int, и, допустим, у c1 были бы другие локальные свойства, они ведь пропадут. Как можно было это исправить? Как-то проверить совпадает ли имя присваемой переменной и имя переменной с которй складываем и затем передать ей словарь __dict__ с локальными атрибутами?
@МаксимАндреев-я1г2 жыл бұрын
Было бы элегантней написать sc = other.seconds if isinstance(other, Click) else other)
@СарматПересветов Жыл бұрын
Вопрос, почему в методе __add__ мы в место того что бы создавать новый обьект класса Clock не можем просто увеличить поле seconds на передаваемое в параметрах число? ведь в таком случае программа будет работать гораздо быстрее, т.к. на создание нового обьекта класса уходит гораздо больше (по компьютерным меркам) времени?
@vladokko Жыл бұрын
Насколько я понимаю, именно потому, что мы не всегда хотим при сложении менять исходный экземпляр класса. Например: c2 = c1 + 100 тут нам не нужно, чтобы менялся c1.seconds. А нужно чтобы функция возвращала новый экземпляр и присваивала его переменной c2
@dubinin_s2 жыл бұрын
Ураа, домашка)))
@МихаилПривалов-ч2я Жыл бұрын
А не проще вместо __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__ сделали?
@Antinormanisto7 ай бұрын
Насчёт домашки, можно либо сделать класс метод который считывает 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
@МаксимМакаров-о5ы2 жыл бұрын
Чтобы не было дублирования кода - оставшиеся операторы сделать через дескрипторы?
@ДмитрийСафронов-р2ъ5 ай бұрын
А зачем мы метод "get_formated" сделали методом класса? Статическим не правильнее?
@Watcherfromfar8 ай бұрын
А зачем нужна __get_formated() функция? Проще же так: return f'{h:02}:{m:02}:{s:02}'. Ладно, буду считать, что это тренировка использования декоратора @classmethod
@alexandreabramtsev9160 Жыл бұрын
поправьте меня, если я не до конца правильно понимаю. Мне кажется что 5:08 минуте метод __get_formatted правильнее сделать статическим методом а не методом класса потому что он используется в методе экземпляра класса (в объекте). Понятно что будет работать и так и так, но все же.... ?
@fWhyJKE Жыл бұрын
Ебать, хорош, мужик. Также подумал. Хорошо что не один такой. Вот так прописал: @staticmethod def ver_sec(x): if not isinstance(x, int): raise TypeError('need int')
@СарматПересветов Жыл бұрын
Да, и я попровал в методе __add__ не создавать новый обьект класса, а изменять поле self.seconds и возвращать ссылку на текущий обьект класса. множественное сложение, и все другие виды сложений так же прекрасно работают. И программа соответственно должна работать быстрее, получается одни плюсы
@selfedu_rus Жыл бұрын
так у вас и значения в объектах, участвующих в сложениях будут тогда меняться
@СарматПересветов Жыл бұрын
@@selfedu_rus ну, вот сейчас посмотрел, не изменились значения в обьектах участвующих в сложении, все работает так как и должно
@selfedu_rus Жыл бұрын
@@СарматПересветов вы в add делаете так: return self.seconds + other тогда да, в самом объекте ничего меняться не будет. Это мой ляп. Но объект все же нужен (в общем случае), т.к. хорошо, что здесь числа складываются, а если бы мы комплексные числа складывали? Тогда без объекта не работало бы.
@СарматПересветов Жыл бұрын
@@selfedu_rus Понял, спасибо)
@Всеволод-ж8д Жыл бұрын
@selfedu Серёга молодец конечно. Но ты не сказал зачем нужны эти методы на практике.
@BritScientist Жыл бұрын
Возможности f-строк в Python позволяют обойтись без метода __get_formatted() вот таким образом: {self.h:>02}
@jamjam3337 Жыл бұрын
спасибо!👏👍
@bandrjuxa2 ай бұрын
Если передать в seconds bool то TypeError не возникнет
@olga_zhu2 жыл бұрын
Добрый день. Сориентируйте, пожалуйста, почему мы присваиваем функции get_formatted уровень класса @classmethod? В нем же не используются атрибуты класса, тот же __DAY. Заранее благодарна!
@selfedu_rus2 жыл бұрын
да, здесь вполне можно прописать статик, все верно!
@olga_zhu2 жыл бұрын
Благодарю за столь оперативный ответ! У меня появился ещё вопрос, если позволите. В коде мы в явном виде прописываем класс Clock, когда нам надо создавать экземпляры объектов для сложения в ф-ии __add__ и когда делаем проверку на принадлежность other к классу. Правильно ли я понимаю, что в данном случае мы никоим образом не можем уйти от прямого обращения к классу, заменив на cls или self, как делали в других уроках? Ведь если наименование класса Clock изменится, то потребуется менять наименование во всех местах, где было прямое обращение. Надеюсь, мой вопрос понятен :)
@olga_zhu2 жыл бұрын
Нашла ответ на свой вопрос у Евгения ниже) Ещё раз спасибо за Вашу подачу материала!
@ЕвгенияМамонова-к7в10 күн бұрын
А если имя класса Clock изменится, как тогда поведет себя строчка return Clock(self.seconds + other). Может бы правильнее return sels.__class__(self.seconds + other)?
@selfedu_rus9 күн бұрын
да, можно так
@ЕвгенияМамонова-к7в9 күн бұрын
@@selfedu_rus вопрос не в том, что так можно. Вопрос в том, что так правильнее. Снимается зависимость от имени класса
@demobunt2 жыл бұрын
В проверке isinstance значения bool проходят как int. Возможно корректнее через type?
@selfedu_rus2 жыл бұрын
да, если нужно четкое сравнение на типы, то конечно, type
@АлексейАлексеев-ц8х9т Жыл бұрын
Сергей, а почему при использовании .rjust(2, 0) вы говорите, что нолик добавляется справа? Ведь он добавляется слева от цифр. Можно конечно предположить, что цифра смотрит на нас "лицом" и то, что мы воспринимаем как слева от неё, это на самом деле справа, но в таком случае при объяснении __add__(self, other) вы объясняете, что other это то, что стоит права от c1
@selfedu_rus Жыл бұрын
да я просто оговорился! Конечно, слева! ))
@АлексейАлексеев-ц8х9т Жыл бұрын
@@selfedu_rus но ведь и метод почему-то начинается на r, а тот, что добавляет символы справа на l, какая-то путаница. А ещё подскажите, планируете ли вы делать на stepik курсы по джанго, базам данных и всему тому, что необходимо для бэкенда? Ролики на эти темы у вас на канале есть, но без практических задач сухая теория совсем не усваивается
@selfedu_rus Жыл бұрын
думал про Django, но на Stepik сложно сделать хороший курс по нему, т.к. это ж фреймворк. Это останавливает.
@АлексейАлексеев-ц8х9т Жыл бұрын
@@selfedu_rus надеюсь, что решение будет найдено. Низкий вам поклон и благодарность за то, что вы для всех нас делаете, учиться у вас - одно удовольствие!
@ravshanmurzaliev418511 ай бұрын
@@selfedu_rus Я думаю если найдете решение и сделайте курс платным будет пользоваться спросом так как нормального курса по джанго нет сейчас
@imadna58106 ай бұрын
Можно тупой вопрос)) Вы говорили, что лучше использовать ссылку на класс, когда его где-то используешь в коде, чтобы не положить программу при замене названия. Можно ли тут использовать cls вместо Clock ?
@PythonSthenics5 ай бұрын
Вместо Clock используй self.__class__, перед и после class двойное нижнее подчеркивание
@DuhaxD2 жыл бұрын
Кажется, что было бы правильнее в методе __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)
@ВладимирФёдоров-н4ь2 жыл бұрын
А Вы прогоните свой вариант на объектах класса например p1 = Class(100), p2 = Class(200) и p3 = p1 + p2, а потом выведите что находится в p1, p2, p3 и поймете почему именно у __iadd__ другая реализация
@interface59002 жыл бұрын
Вроде неплохо получилось 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
@ask9712 жыл бұрын
А можно подсказку по том, как без дублирования кода засунуть все арифметические операции в класс, ведь по сути код для маг метода __add__ отличается от __sub__, __mul__, __truediv__ только названием метода и конкретной операцией. Через каррирование загнав все маг методы в словарь с соответствующим оператором, или видео урок про дескрипторы как раз здесь и можно применить, или я вовсе перемудрил и решение куда проще? Проверки на int, Clock тоже можно было засунуть в отдельный @classmetod для соблюдения "dry" это бы упростило читабельность и громоздкость кода? Заранее спасибо..
@Koshsky-f7y2 жыл бұрын
Я думаю словарь нужно составить 'операция':'знак операции' и использовать eval()
@ГуняГуняев-ю7ф2 жыл бұрын
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 объектами КОРОЧЕ ПАСАНЫ ,,,,Я ЭТИ ВАШИ МАГМЕТОДЫ НА ДЕСКРИПТОРЕ ВЕРТЕЛ КАК ХОТЕЛ))))))
@ibrahimoglu2 жыл бұрын
👍
@Konstantin_Stalnov Жыл бұрын
Почему вначале при сложении мы создаём новый Экземпляр Класса, а потом (+=) мы просто меняем значение Атрибута Экземпляра Класса. Почему в первом случае мы не можем поменять? Зачем нам создавать новый Экземпляр Класса.
@romankucheruk89742 жыл бұрын
Спасибо крутое ДЗ: 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())
@ГуняГуняев-ю7ф2 жыл бұрын
🤣все с точностью донаоборот....не прописывать каждую функцию и декорировать ее,а создать дескриптор который будет описывать всю шоблу этих функций)))))....просто поэкспериментируй с конструкцией __get__(): def inner(other): return ..... return inner
@cosmoboyplays4085 Жыл бұрын
во, твой вариант мне прям понравился
@eazy8537 Жыл бұрын
А зачем часы ещё делить по остатку на 24, если в принципе их не может быть больше 24, благодаря делению секунд на __DAY, или я чего-то не понимаю? И почему мы используем метод класса вместо статик метода, если мы не работаем с атрибутами класса?
@selfedu_rus Жыл бұрын
на 24 делю для надежности, чтобы точно не было больше (привычка везде делать "защиту от дурака"), а метод да, здесь вполне и статик подойдет.
@backsoul4411 ай бұрын
почему "Магические"?
@ЕвгенияМамонова-к7в10 күн бұрын
А можно хоть одну прогу написать, чтобы без raise? Чтобы заставить пользователя ввести именно то, что необходимо ввести и не прерывать, как сумасшедший выполнение программы (особенно в примере использования объекта property)? Кому такая программа будет нужна, если на каждый неправильный шаг юзверя она будет вываливаться? Так себе подход, короче.
@user-ph7nw6tr9b6 ай бұрын
При попытке реализовать def __rsub__(self, other): return self - other он вычитает из объекта число, хотя хотелось бы наоборот. Как?
@user-ph7nw6tr9b6 ай бұрын
Решил проблему простой заменой знака результата. Это нормально, или как-то ещё делают?
@РустамКаримов-с2с2 жыл бұрын
Не понятно как происходит вызов метода radd. Если я выполняю с1 + 100, происходит вызов с1.__add__(100). Вызывая 100 + с1, я ожидаю вызов 100.__add__(c1), т. Е метод класса int. Как интерпретатор понимает, что нужно вызвать именно radd нашего класса?
@selfedu_rus2 жыл бұрын
здесь сам интерпретатор уже "соображает", что нужно вызвать именно radd, т.к. такой метод определен в c1
@nomadicus77 Жыл бұрын
Ех зная это можно было бы задание в 3.3 последние легче сделать)))
@ЕвгенияМамонова-к7в10 күн бұрын
c1.seconds = c1.seconds + 100. А что, c1.seconds += 100 уже не работает в Python?
@selfedu_rus9 күн бұрын
за это отвечает магический метод iadd
@ЕвгенияМамонова-к7в9 күн бұрын
@selfedu_rus так он под капотом у главного родителя object
@sergeykot68743 ай бұрын
После переопределения метода __iadd__ решил убедиться, что новый экземпляр с1 не создается. Для этого выполнил печать следующим образом: c1 = Clock(1000) print("c1 =", c1, "=", c1.get_time()) c1 += 100 print("c1 =", c1, "=", c1.get_time()) в результате получил: c1 = = 00:16:40 __iadd__ c1 = = 00:20:00 т.е., адрес изменился, значит, новый экземпляр таки был создан?
@sergeykot68743 ай бұрын
Комментарий неправильный, я ошибся при копировании реализации метода. после исправления ошибки получил: c1 = = 00:21:40 __iadd__ c1 = = 00:23:20 Новый экземпляр не создается
@ВадимАхмадуллин-д6ъ2 жыл бұрын
зачем было городить еще и __get_formatted() ? можно было все уместить в f-строку
@IdenasTuringTest Жыл бұрын
Очень советую избегать этих магических методов (именно этих 4-х). Лучше сделайте отдельные обычные методы add(), sub() или назовите какими-нибудь increase(), decrease(). И в методах просто соответственно увеличивайте или уменьшайте свойство seconds. Если же вы все-таки решили добавить логику сложения объектов с этими маг-методами, то обязательно протестируйте результат на всех возможных вариантах: объект справа от плюса, слева от плюса, складываются два объекта и результат присваивается третьему. И обязательно каждый раз проверяйте все свойства (в примере из видео это одно свойство seconds) всех объектов. А вот если вы создадите дочерний класс от этого, гемор вам обеспечен 😁
@ИгорьХамула-х7я2 жыл бұрын
Подскажите пожалуйста зачем нужен return self в конце метода __iadd__. буду благодарен
@selfedu_rus2 жыл бұрын
Чтобы результат можно было присвоить какой-либо другой переменной (ссылку на объект). Если этого не требуется, то можно не возвращать (вроде бы).
@J1mDGriz Жыл бұрын
правильно я понимаю, что метод __add__ он более общий по сравнению с radd и iadd?
@Sergiypsm2 жыл бұрын
Решение задачи поставленной в конце видео: использовать менеджер контекста width? Или это неправильный путь?
@selfedu_rus2 жыл бұрын
не совсем понятно для чего with?
@Sergiypsm2 жыл бұрын
@@selfedu_rus да, глупость я сморозил. Скорее, опять нужна какая-то магия.
@Sergiypsm2 жыл бұрын
Вроде получилось colab.research.google.com/drive/1M4Cdv82HeVBcQE-kn-zTRzjIWFNbrjpt?usp=sharing
@ГуняГуняев-ю7ф2 жыл бұрын
попытался превратить магию методов в вуду дескрипторов и замыканий 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 объектами КОРОЧЕ ПАСАНЫ ,,,,Я ЭТИ ВАШИ МАГМЕТОДЫ НА ДЕСКРИПТОРЕ ВЕРТЕЛ КАК ХОТЕЛ))))))
@J1mDGriz Жыл бұрын
почему на 23 строчке нельзя было написать if isinstance(other, Clock): other = other.seconds return Clock(self.seconds + other) без введения доп переменной
@johnmazepa Жыл бұрын
а зачем мы в качестве возвращаемого значения метода __add__ устанавливаем НОВЫЙ объект класса Clock с увеличенным количеством секунд: return Clock(self.seconds + other) вместо того, чтобы просто увеличить значение для текущего объекта: return self.seconds + other ?
@johnmazepa Жыл бұрын
или это просто демонстрация того, как можно манипулировать данными, а нам на практике уже нужно будет действовать на своё усмотрение в зависимости от ситуации?
@selfedu_rus Жыл бұрын
@@johnmazepa если нужно несколько слагаемых, например: a+b+c+d
@ChilikovAleksandr Жыл бұрын
В данной реализации вернется количество секунд, а не экземпляр класса 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
@ilyazheprog2 жыл бұрын
Меня месяц тревожит вопрос, проиллюстрирую на примере из видео: c1 = Clock(1000) c1 = c1 + 100 Как сделать, чтобы работало и c1 = 100 + c1 ? Заранее спасибо)
@selfedu_rus2 жыл бұрын
__radd__
@miraiggm Жыл бұрын
Дякую за відео, але не дуже зрозумів тут 12:02, що означає sc = other.seconds
@selfedu_rus Жыл бұрын
Там при сложении операнд справа может быть как число, так и объект Clock. Отсюда и появляется проверка в add.
@КостяГорохов-б6с2 жыл бұрын
Не понятно, если эти методы из коробки идут, то зачем в них еще столько кода писать, почему они сразу в две или одну строчку не идут? или я не про то? )
@selfedu_rus2 жыл бұрын
не про то, можно их вообще не переопределять, если не нужно, в противном случае прописываем свой алгоритм, а сколько строчек кода - это зависит от задачи
@sladge172 жыл бұрын
Можно ли в iadd не делать return self, ведь на уже изменили значение атрибута в экземпляре, или будет ошибка?
@selfedu_rus2 жыл бұрын
нужно, т.к. там идет присваивание результата операнду слева от оператора +=
@sladge172 жыл бұрын
Спасибо за ответ
@skamikus2 жыл бұрын
@@selfedu_rus вряд-ли увижу ответ, но попытаюсь) В __radd__ мы получаем self и изменяя экземпляр через него, по сути методом и запишем значение, или я не прав? self ведь получается берет как раз что нам и нужно...
@skamikus2 жыл бұрын
Все таки проверил и даже вроде осознал return нужен! ))
@konstantinpluzhnikov48622 жыл бұрын
не думай о секундах свысока.
@return_11012 жыл бұрын
У меня освободилось кучу времени, и прохожу курс в степик. (Но я очень далеко... На 3.7... ((() Этот курс будет там еще долго? Уважаю ваш труд. Вы гений.
@selfedu_rus2 жыл бұрын
Спасибо! Да, я надеюсь, курс надолго )
@ИгорьХамула-х7я2 жыл бұрын
@@selfedu_rus у вас есть курс на степике?
@selfedu_rus2 жыл бұрын
@@ИгорьХамула-х7я по ООП нет
@АндрейОт2 жыл бұрын
@@ИгорьХамула-х7я есть))
@jaksonmillkaАй бұрын
Урок #14 = Пройден
@SASka-ct7zj2 жыл бұрын
Как понять незначищий ноль справа , а потом говорите если 1 2 или то будет 0 1 0 2 и тд., где логика? Там помойму число больше нуля вправа едет а нули влево
@kazybekkydyrbai86322 жыл бұрын
Да ладно к словам придираться, главное суть же объяснили и код правильно работает. rjust делает выравнивание с право(right).
@Anna_tails Жыл бұрын
а __sum__
@ВалерийМакаров-ц8ж11 ай бұрын
Материал и подача хорошие, но английский плох. Рекомендую подучить произношение слов, которые используются в программировании. Неправильное произношение вызывает недоумение у незнающих людей. Ещё было бы полезно объяснять полное название методов, например mul - multiply(умножать). В данном видео метод __add__ читается как "эд" (добавить)
@nothman5 ай бұрын
Не мог проще пример взять?!!!! Кучу воды наговорил, пока до маг. метода добрался.
@misterx43774 ай бұрын
опять бессмысленное усложнение объяснения на ровном месте, с этими секундами, сначала надо понять суть на примитиве, потом рассчитывать космический корабль, часть ресурсов мозга уходит что бы вникнуть ещё и в пример ...