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

Поделиться
HTML-код
  • Опубликовано: 20 сен 2024

Комментарии • 121

  • @NewSouthMjos
    @NewSouthMjos 2 года назад +59

    Могу добавить, что при реализации __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 Год назад +2

      я бы сделал удобочитаемей:
      def __add__(self, sec):
      self.__seconds += sec
      return self

    • @IdenasTuringTest
      @IdenasTuringTest Год назад +4

      @@minecraftlp6306 В твоем варианте меняется сам объект. Тогда в примере выше (b = a + 100) получится, что в результате такого "сложения" изменится сам объект "a" и еще оба идентификатора (и "a" и "b") будут ссылаться на один и тот же объект

  • @ИгорьЛатуха
    @ИгорьЛатуха 2 года назад +48

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

  • @андрейхоменко-и5я
    @андрейхоменко-и5я 2 года назад +28

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

  • @keribirinto
    @keribirinto 10 месяцев назад +5

    Думаю, так будет уже лучше, я вынес в отдельную функцию основу кода и в методах уже вызывал ее и писал знаки
    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)

  • @ravshanmurzaliev4185
    @ravshanmurzaliev4185 9 месяцев назад +1

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

  • @РайнГослинг-р4к
    @РайнГослинг-р4к 4 месяца назад +3

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

  • @pphan_
    @pphan_ 8 месяцев назад +1

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

  • @rukigaki
    @rukigaki 11 месяцев назад +2

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

    • @selfedu_rus
      @selfedu_rus  11 месяцев назад +1

      Привычка все проверять на всех уровнях.

  • @andredru4278
    @andredru4278 6 месяцев назад +1

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

  • @igorratnik2357
    @igorratnik2357 Год назад +1

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

  • @БогданСыроватский-б6ж

    Для класса 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-zt4wx1ks6z
    @user-zt4wx1ks6z 2 года назад +1

    Сергей, спасибо за уроки!!!

  • @МамонтовОлег-в9о
    @МамонтовОлег-в9о 2 года назад +3

    класс! Серёга лучший!

  • @anvarx1
    @anvarx1 Год назад

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

  • @andredru4278
    @andredru4278 6 месяцев назад +1

    Спасибо. Очень интересно.

  • @romankucheruk8974
    @romankucheruk8974 2 года назад +9

    Спасибо крутое ДЗ:
    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ф
      @ГуняГуняев-ю7ф 2 года назад

      🤣все с точностью донаоборот....не прописывать каждую функцию и декорировать ее,а создать дескриптор который будет описывать всю шоблу этих функций)))))....просто поэкспериментируй с конструкцией __get__():
      def inner(other):
      return .....
      return inner

    • @cosmoboyplays4085
      @cosmoboyplays4085 Год назад

      во, твой вариант мне прям понравился

  • @ЗахарСавчин-ж5п
    @ЗахарСавчин-ж5п Год назад +1

    Очень доступно, спасибо!

  • @ДимычДимон-г3ю
    @ДимычДимон-г3ю 9 месяцев назад +1

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

  • @МихаилПривалов-ч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__ сделали?

  • @РустамРаджабов-ц3м
    @РустамРаджабов-ц3м 6 месяцев назад +1

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

  • @VladimirOnokhov
    @VladimirOnokhov Год назад +1

    спасибо за урок!

  • @Блинчик-н4о
    @Блинчик-н4о Год назад +4

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

  • @TwilightNyann
    @TwilightNyann Год назад +1

    Это гениально

  • @uladzislawchyrets
    @uladzislawchyrets 2 года назад +1

    Спасибо за уроки

  • @МаксимАндреев-я1г
    @МаксимАндреев-я1г 2 года назад +5

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

  • @BritScientist
    @BritScientist 10 месяцев назад

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

  • @dubinin_s
    @dubinin_s 2 года назад +3

    Ураа, домашка)))

  • @jamjam3337
    @jamjam3337 Год назад +1

    спасибо!👏👍

  • @СарматПересветов
    @СарматПересветов Год назад +1

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

    • @selfedu_rus
      @selfedu_rus  Год назад

      так у вас и значения в объектах, участвующих в сложениях будут тогда меняться

    • @СарматПересветов
      @СарматПересветов Год назад

      @@selfedu_rus ну, вот сейчас посмотрел, не изменились значения в обьектах участвующих в сложении, все работает так как и должно

    • @selfedu_rus
      @selfedu_rus  Год назад

      @@СарматПересветов вы в add делаете так:
      return self.seconds + other
      тогда да, в самом объекте ничего меняться не будет. Это мой ляп. Но объект все же нужен (в общем случае), т.к. хорошо, что здесь числа складываются, а если бы мы комплексные числа складывали? Тогда без объекта не работало бы.

    • @СарматПересветов
      @СарматПересветов Год назад

      @@selfedu_rus Понял, спасибо)

  • @ДмитрийСафронов-р2ъ
    @ДмитрийСафронов-р2ъ 3 месяца назад +1

    А зачем мы метод "get_formated" сделали методом класса? Статическим не правильнее?

  • @BritScientist
    @BritScientist 10 месяцев назад +1

    Возможности f-строк в Python позволяют обойтись без метода __get_formatted() вот таким образом: {self.h:>02}

  • @interface5900
    @interface5900 2 года назад +3

    Вроде неплохо получилось
    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

  • @Antinormanisto
    @Antinormanisto 6 месяцев назад +1

    Насчёт домашки, можно либо сделать класс метод который считывает 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

  • @СарматПересветов
    @СарматПересветов Год назад +3

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

    • @vladokko
      @vladokko Год назад +1

      Насколько я понимаю, именно потому, что мы не всегда хотим при сложении менять исходный экземпляр класса. Например:
      c2 = c1 + 100
      тут нам не нужно, чтобы менялся c1.seconds. А нужно чтобы функция возвращала новый экземпляр и присваивала его переменной c2

  • @Всеволод-ж8д
    @Всеволод-ж8д Год назад +1

    @selfedu Серёга молодец конечно. Но ты не сказал зачем нужны эти методы на практике.

  • @Watcherfromfar
    @Watcherfromfar 6 месяцев назад +2

    А зачем нужна __get_formated() функция? Проще же так: return f'{h:02}:{m:02}:{s:02}'. Ладно, буду считать, что это тренировка использования декоратора @classmethod

  • @IdenasTuringTest
    @IdenasTuringTest Год назад +1

    Очень советую избегать этих магических методов (именно этих 4-х). Лучше сделайте отдельные обычные методы add(), sub() или назовите какими-нибудь increase(), decrease(). И в методах просто соответственно увеличивайте или уменьшайте свойство seconds.
    Если же вы все-таки решили добавить логику сложения объектов с этими маг-методами, то обязательно протестируйте результат на всех возможных вариантах: объект справа от плюса, слева от плюса, складываются два объекта и результат присваивается третьему. И обязательно каждый раз проверяйте все свойства (в примере из видео это одно свойство seconds) всех объектов.
    А вот если вы создадите дочерний класс от этого, гемор вам обеспечен 😁

  • @alexandreabramtsev9160
    @alexandreabramtsev9160 Год назад +3

    поправьте меня, если я не до конца правильно понимаю. Мне кажется что 5:08 минуте метод __get_formatted правильнее сделать статическим методом а не методом класса потому что он используется в методе экземпляра класса (в объекте). Понятно что будет работать и так и так, но все же.... ?

    • @fWhyJKE
      @fWhyJKE Год назад

      Ебать, хорош, мужик. Также подумал. Хорошо что не один такой. Вот так прописал:
      @staticmethod
      def ver_sec(x):
      if not isinstance(x, int):
      raise TypeError('need int')

  • @DuhaxD
    @DuhaxD 2 года назад +3

    Кажется, что было бы правильнее в методе __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ь
      @ВладимирФёдоров-н4ь 2 года назад +3

      А Вы прогоните свой вариант на объектах класса например p1 = Class(100), p2 = Class(200) и p3 = p1 + p2, а потом выведите что находится в p1, p2, p3 и поймете почему именно у __iadd__ другая реализация

  • @nomadicus77
    @nomadicus77 Год назад +1

    Ех зная это можно было бы задание в 3.3 последние легче сделать)))

  • @imadna5810
    @imadna5810 4 месяца назад +1

    Можно тупой вопрос)) Вы говорили, что лучше использовать ссылку на класс, когда его где-то используешь в коде, чтобы не положить программу при замене названия.
    Можно ли тут использовать cls вместо Clock ?

    • @PythonSthenics
      @PythonSthenics 3 месяца назад

      Вместо Clock используй self.__class__, перед и после class двойное нижнее подчеркивание

  • @user-gs3dd2le1e
    @user-gs3dd2le1e 2 года назад +3

    зачем было городить еще и __get_formatted() ? можно было все уместить в f-строку

  • @Konstantin_Stalnov
    @Konstantin_Stalnov Год назад +1

    Почему вначале при сложении мы создаём новый Экземпляр Класса, а потом (+=) мы просто меняем значение Атрибута Экземпляра Класса.
    Почему в первом случае мы не можем поменять? Зачем нам создавать новый Экземпляр Класса.

  • @МаксимМакаров-о5ы
    @МаксимМакаров-о5ы Год назад +2

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

  • @bandrjuxa
    @bandrjuxa 11 дней назад +1

    Если передать в seconds bool то TypeError не возникнет

  • @eazy8537
    @eazy8537 Год назад +1

    А зачем часы ещё делить по остатку на 24, если в принципе их не может быть больше 24, благодаря делению секунд на __DAY, или я чего-то не понимаю? И почему мы используем метод класса вместо статик метода, если мы не работаем с атрибутами класса?

    • @selfedu_rus
      @selfedu_rus  Год назад

      на 24 делю для надежности, чтобы точно не было больше (привычка везде делать "защиту от дурака"), а метод да, здесь вполне и статик подойдет.

  • @ask971
    @ask971 2 года назад +6

    А можно подсказку по том, как без дублирования кода засунуть все арифметические операции в класс, ведь по сути код для маг метода __add__ отличается от __sub__, __mul__, __truediv__ только названием метода и конкретной операцией. Через каррирование загнав все маг методы в словарь с соответствующим оператором, или видео урок про дескрипторы как раз здесь и можно применить, или я вовсе перемудрил и решение куда проще?
    Проверки на int, Clock тоже можно было засунуть в отдельный @classmetod для соблюдения "dry" это бы упростило читабельность и громоздкость кода?
    Заранее спасибо..

    • @Koshsky-f7y
      @Koshsky-f7y 2 года назад

      Я думаю словарь нужно составить 'операция':'знак операции' и использовать eval()

    • @ГуняГуняев-ю7ф
      @ГуняГуняев-ю7ф 2 года назад +4

      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 объектами
      КОРОЧЕ ПАСАНЫ ,,,,Я ЭТИ ВАШИ МАГМЕТОДЫ НА ДЕСКРИПТОРЕ ВЕРТЕЛ КАК ХОТЕЛ))))))

  • @АлексейАлексеев-ц8х9т

    Сергей, а почему при использовании .rjust(2, 0) вы говорите, что нолик добавляется справа? Ведь он добавляется слева от цифр.
    Можно конечно предположить, что цифра смотрит на нас "лицом" и то, что мы воспринимаем как слева от неё, это на самом деле справа, но в таком случае при объяснении __add__(self, other) вы объясняете, что other это то, что стоит права от c1

    • @selfedu_rus
      @selfedu_rus  Год назад

      да я просто оговорился! Конечно, слева! ))

    • @АлексейАлексеев-ц8х9т
      @АлексейАлексеев-ц8х9т Год назад +1

      @@selfedu_rus но ведь и метод почему-то начинается на r, а тот, что добавляет символы справа на l, какая-то путаница.
      А ещё подскажите, планируете ли вы делать на stepik курсы по джанго, базам данных и всему тому, что необходимо для бэкенда? Ролики на эти темы у вас на канале есть, но без практических задач сухая теория совсем не усваивается

    • @selfedu_rus
      @selfedu_rus  Год назад +1

      думал про Django, но на Stepik сложно сделать хороший курс по нему, т.к. это ж фреймворк. Это останавливает.

    • @АлексейАлексеев-ц8х9т
      @АлексейАлексеев-ц8х9т Год назад +1

      @@selfedu_rus надеюсь, что решение будет найдено.
      Низкий вам поклон и благодарность за то, что вы для всех нас делаете, учиться у вас - одно удовольствие!

    • @ravshanmurzaliev4185
      @ravshanmurzaliev4185 9 месяцев назад

      ​@@selfedu_rus Я думаю если найдете решение и сделайте курс платным будет пользоваться спросом так как нормального курса по джанго нет сейчас

  • @ibrahimoglu
    @ibrahimoglu 2 года назад +1

    👍

  • @sergeykot6874
    @sergeykot6874 Месяц назад

    После переопределения метода __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
    т.е., адрес изменился, значит, новый экземпляр таки был создан?

    • @sergeykot6874
      @sergeykot6874 Месяц назад

      Комментарий неправильный, я ошибся при копировании реализации метода. после исправления ошибки получил:
      c1 = = 00:21:40
      __iadd__
      c1 = = 00:23:20
      Новый экземпляр не создается

  • @olga_zhu
    @olga_zhu 2 года назад +2

    Добрый день. Сориентируйте, пожалуйста, почему мы присваиваем функции get_formatted уровень класса @classmethod? В нем же не используются атрибуты класса, тот же __DAY. Заранее благодарна!

    • @selfedu_rus
      @selfedu_rus  2 года назад +4

      да, здесь вполне можно прописать статик, все верно!

    • @olga_zhu
      @olga_zhu 2 года назад +1

      Благодарю за столь оперативный ответ!
      У меня появился ещё вопрос, если позволите. В коде мы в явном виде прописываем класс Clock, когда нам надо создавать экземпляры объектов для сложения в ф-ии __add__ и когда делаем проверку на принадлежность other к классу. Правильно ли я понимаю, что в данном случае мы никоим образом не можем уйти от прямого обращения к классу, заменив на cls или self, как делали в других уроках? Ведь если наименование класса Clock изменится, то потребуется менять наименование во всех местах, где было прямое обращение. Надеюсь, мой вопрос понятен :)

    • @olga_zhu
      @olga_zhu 2 года назад +2

      Нашла ответ на свой вопрос у Евгения ниже)
      Ещё раз спасибо за Вашу подачу материала!

  • @jaksonmillka
    @jaksonmillka 2 дня назад +1

    Урок #14 = Пройден

  • @return_1101
    @return_1101 2 года назад +2

    У меня освободилось кучу времени, и прохожу курс в степик. (Но я очень далеко... На 3.7... ((()
    Этот курс будет там еще долго?
    Уважаю ваш труд. Вы гений.

    • @selfedu_rus
      @selfedu_rus  2 года назад +2

      Спасибо! Да, я надеюсь, курс надолго )

    • @ИгорьХамула-х7я
      @ИгорьХамула-х7я 2 года назад

      @@selfedu_rus у вас есть курс на степике?

    • @selfedu_rus
      @selfedu_rus  2 года назад

      @@ИгорьХамула-х7я по ООП нет

    • @АндрейОт
      @АндрейОт 2 года назад

      @@ИгорьХамула-х7я есть))

  • @demobunt
    @demobunt 2 года назад +2

    В проверке isinstance значения bool проходят как int. Возможно корректнее через type?

    • @selfedu_rus
      @selfedu_rus  2 года назад +1

      да, если нужно четкое сравнение на типы, то конечно, type

  • @J1mDGriz
    @J1mDGriz Год назад

    почему на 23 строчке нельзя было написать
    if isinstance(other, Clock):
    other = other.seconds
    return Clock(self.seconds + other)
    без введения доп переменной

  • @user-ym4uf8bj6f
    @user-ym4uf8bj6f Год назад +1

    Дякую за відео, але не дуже зрозумів тут 12:02, що означає sc = other.seconds

    • @selfedu_rus
      @selfedu_rus  Год назад

      Там при сложении операнд справа может быть как число, так и объект Clock. Отсюда и появляется проверка в add.

  • @КостяГорохов-б6с
    @КостяГорохов-б6с 2 года назад +2

    Не понятно, если эти методы из коробки идут, то зачем в них еще столько кода писать, почему они сразу в две или одну строчку не идут? или я не про то? )

    • @selfedu_rus
      @selfedu_rus  2 года назад +1

      не про то, можно их вообще не переопределять, если не нужно, в противном случае прописываем свой алгоритм, а сколько строчек кода - это зависит от задачи

  • @РустамКаримов-с2с
    @РустамКаримов-с2с 2 года назад +1

    Не понятно как происходит вызов метода radd. Если я выполняю с1 + 100, происходит вызов с1.__add__(100). Вызывая 100 + с1, я ожидаю вызов 100.__add__(c1), т. Е метод класса int. Как интерпретатор понимает, что нужно вызвать именно radd нашего класса?

    • @selfedu_rus
      @selfedu_rus  2 года назад +1

      здесь сам интерпретатор уже "соображает", что нужно вызвать именно radd, т.к. такой метод определен в c1

  • @backsoul44
    @backsoul44 9 месяцев назад +2

    почему "Магические"?

  • @Sergiypsm
    @Sergiypsm 2 года назад

    Решение задачи поставленной в конце видео: использовать менеджер контекста width? Или это неправильный путь?

    • @selfedu_rus
      @selfedu_rus  2 года назад

      не совсем понятно для чего with?

    • @Sergiypsm
      @Sergiypsm 2 года назад

      @@selfedu_rus да, глупость я сморозил. Скорее, опять нужна какая-то магия.

    • @Sergiypsm
      @Sergiypsm 2 года назад +1

      Вроде получилось colab.research.google.com/drive/1M4Cdv82HeVBcQE-kn-zTRzjIWFNbrjpt?usp=sharing

    • @ГуняГуняев-ю7ф
      @ГуняГуняев-ю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 объектами
      КОРОЧЕ ПАСАНЫ ,,,,Я ЭТИ ВАШИ МАГМЕТОДЫ НА ДЕСКРИПТОРЕ ВЕРТЕЛ КАК ХОТЕЛ))))))

  • @johnmazepa
    @johnmazepa Год назад

    а зачем мы в качестве возвращаемого значения метода __add__ устанавливаем НОВЫЙ объект класса Clock с увеличенным количеством секунд:
    return Clock(self.seconds + other)
    вместо того, чтобы просто увеличить значение для текущего объекта:
    return self.seconds + other
    ?

    • @johnmazepa
      @johnmazepa Год назад

      или это просто демонстрация того, как можно манипулировать данными, а нам на практике уже нужно будет действовать на своё усмотрение в зависимости от ситуации?

    • @selfedu_rus
      @selfedu_rus  Год назад

      @@johnmazepa если нужно несколько слагаемых, например: a+b+c+d

    • @ChilikovAleksandr
      @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

  • @user-ph7nw6tr9b
    @user-ph7nw6tr9b 4 месяца назад

    При попытке реализовать def __rsub__(self, other):
    return self - other
    он вычитает из объекта число, хотя хотелось бы наоборот. Как?

    • @user-ph7nw6tr9b
      @user-ph7nw6tr9b 4 месяца назад

      Решил проблему простой заменой знака результата. Это нормально, или как-то ещё делают?

  • @J1mDGriz
    @J1mDGriz Год назад

    правильно я понимаю, что метод __add__ он более общий по сравнению с radd и iadd?

  • @konstantinpluzhnikov4862
    @konstantinpluzhnikov4862 Год назад +1

    не думай о секундах свысока.

  • @ilyazheprog
    @ilyazheprog 2 года назад

    Меня месяц тревожит вопрос, проиллюстрирую на примере из видео:
    c1 = Clock(1000)
    c1 = c1 + 100
    Как сделать, чтобы работало и c1 = 100 + c1 ? Заранее спасибо)

  • @ИгорьХамула-х7я
    @ИгорьХамула-х7я 2 года назад

    Подскажите пожалуйста зачем нужен return self в конце метода __iadd__. буду благодарен

    • @selfedu_rus
      @selfedu_rus  2 года назад

      Чтобы результат можно было присвоить какой-либо другой переменной (ссылку на объект). Если этого не требуется, то можно не возвращать (вроде бы).

  • @sladge17
    @sladge17 2 года назад

    Можно ли в iadd не делать return self, ведь на уже изменили значение атрибута в экземпляре, или будет ошибка?

    • @selfedu_rus
      @selfedu_rus  2 года назад

      нужно, т.к. там идет присваивание результата операнду слева от оператора +=

    • @sladge17
      @sladge17 2 года назад +1

      Спасибо за ответ

    • @skamikus
      @skamikus 2 года назад

      @@selfedu_rus вряд-ли увижу ответ, но попытаюсь)
      В __radd__ мы получаем self и изменяя экземпляр через него, по сути методом и запишем значение, или я не прав? self ведь получается берет как раз что нам и нужно...

    • @skamikus
      @skamikus 2 года назад

      Все таки проверил и даже вроде осознал return нужен! ))

  • @SASka-ct7zj
    @SASka-ct7zj 2 года назад

    Как понять незначищий ноль справа , а потом говорите если 1 2 или то будет 0 1 0 2 и тд., где логика? Там помойму число больше нуля вправа едет а нули влево

    • @kazybekkydyrbai8632
      @kazybekkydyrbai8632 2 года назад

      Да ладно к словам придираться, главное суть же объяснили и код правильно работает. rjust делает выравнивание с право(right).

  • @Anna_tails
    @Anna_tails 11 месяцев назад

    а __sum__

  • @ВалерийМакаров-ц8ж
    @ВалерийМакаров-ц8ж 9 месяцев назад +1

    Материал и подача хорошие, но английский плох. Рекомендую подучить произношение слов, которые используются в программировании. Неправильное произношение вызывает недоумение у незнающих людей. Ещё было бы полезно объяснять полное название методов, например mul - multiply(умножать).
    В данном видео метод __add__ читается как "эд" (добавить)

  • @nothman
    @nothman 3 месяца назад +2

    Не мог проще пример взять?!!!! Кучу воды наговорил, пока до маг. метода добрался.

  • @misterx4377
    @misterx4377 2 месяца назад

    опять бессмысленное усложнение объяснения на ровном месте, с этими секундами, сначала надо понять суть на примитиве, потом рассчитывать космический корабль, часть ресурсов мозга уходит что бы вникнуть ещё и в пример ...