#7. Магические методы __setattr__, __getattribute__, __getattr__ и __delattr__ | ООП Python
HTML-код
- Опубликовано: 24 ноя 2021
- Курс по Python ООП: stepik.org/a/116336
Класс как пространство имен. Порядок обращения к атрибутам класса и к атрибутам его экземпляров. Магические методы при работе с атрибутами класса: _setattr__, __getattribute__, __getattr_ и _delattr_
Инфо-сайт: proproprogs.ru/python_oop
Telegram-канал: t.me/python_selfedu
Объяснение "Зачем" - это ключевой момент, как мне кажется. Без этого все эти методы просто набор команд, которые выветрятся из памяти без применения. А понимая зачем, больше шансов, что они вспомнятся в нужный момент)))
Особая благодарность за разъяснения "зачем".
СПАСИБО Вам за Ваш труд! Ваши лекции лучшие из тех, что встречаются на просторах Ютуба.
Ролик всего лишь чуть более пятнадцати минут, а чтобы утоптать его в голову, понадобился без малого целый день. И то степень усвоения материала - иллюзия понимания. Автору очередное большое спасибо.
Как же точно вы описали мое состояние. А я все понять не мог, что именно не так.
сидишь и пробуешь написать ручками, а потом что-то ради интереса поменять, чаще всего, когда непонятно "а как это повлияет на результат и сойдется ли с моим ожидаемый". У меня на каждую тему благодаря такому методу 30-40 мин уходит
__ЧЕКПОИНТ__
Смотрю видео уроки уже 7 день подряд пытаясь изучить ооп и у меня отлично получается! Спасибо огромное Сергею,за предоставленные знания,а я прошу пожелать мне удачи в понимании следующих тем)
Спасибо за вашу работу! Уверен, буду использовать этот раздел (ооп) в своих программах (пока такой уровень)). Отдельное спасибо за очень подробное объяснение основ (в первых видео этого плейлиста), это сильно упрощает последующее обучение. Удачи вам в продвижении!
Спасибо за лёгкую и приятную подачу сухого материала! Ваше речевые обороты искренне радуют - "будем полагать, что мы теперь хорошо понимаем" - :)
Сергей, жму Вам руку! Отличный материал! Смотрю как уменьшается количество просмотров и лайков от урока к уроку, все таки курс ориентирован не на новичков. Но для тех кто знаком с ООП ваш материал просто клад!
Сергей, спасибо за труд! Очень качественный материал и доходчивое разъяснение
Огромное спасибо за такую интересную и подробную подачу материала! Вы очень талантливый преподаватель и делаете большое дело, Спасибо!
Огромное спасибо! Всегда любил учиться по системе "Если тема не понятна, меняй спикеров/учителей" и на вашем примере сработало, вы первый кто сказал что-то , что не говорили остальные и все встало на свое место :) 4:25 сижу такой и бамс, все понял , спасибо!🤩
Большое спасибо Вам за такие уроки!
Отличный урок!!! Буду смотреть все ваши уроки... Спасибо огромное !!!
Спасибо! Очень четкое объяснение магических методов.
Сергей, доброго времени суток. Вас беспокоит Бог. За ваш бескорыстный труд я приготовил вам место в раю. Увидимся не скоро: я вам нормально так жизню продлил. Спасибо вам и всего светлого!
Молодец программист, начал хоть что то понимать в ООП
Вау! Спасибо большое!
Это многое упрощает😅
Спасибо за классные уроки! И мне сердечко!)
Сергей, благодарю!! 👍🔥💯
Спасибо. Отличные примеры!
Спасибо за урок! Не знал и использовал костыли :)
Крутой урок..Спасибо большое
Интересное занятие! Можно добавлять гибкость в свой код, этими методами!
Блин, ютуб, для таких видео давно должна быть функция "поставить тыщу лайков" !!!!
Супергениальный урок!!!
Этот урок слушал 5 раз.
Спасибо за урок
Лучший! Спасибо
Спасибо
Может кому - то так станет понятно если он не понял. Немного забегу вперед, поскольку я сначала проходил менее подробный курс и там было про наследование, то я лично смог это понять относительно легко именно поэтому, как мне кажется. Когда мы наследуем любой класс в другой класс, мы это делаем по средствам скобок после названия класса и прописываем внутри название класса от которого наследуем, в случае с классом object мы неявно наследуем его по умолчанию, как тут и сказано собственно. Мы наследуем все атрибуты класса, кроме понятно защищенных от этого. И в данном случае хоть мы и не видим все эти атрибуты в теле класса, мы всеровно можем к ним обращаться, а когда мы прописываем метод внутри дочернего класса с названием которое уже существует в материнском классе, то мы выполняем так называемое переопределение атрибута, то есть теперь у нас есть атрибут с таким же названием как в материнском классе, но выполняет он теперь при вывозе тот функционал который мы прописали. А таким синтаксисом: название_материнского_класса.название_материнского_атрибута(необходимые аргументы) мы как раз возвращаем весь тот функционал что содержится внутри материнского метода с таким же названием. Как я понимаю переопределение метода класса происходит по такому же принципу как создание атрибута для экземпляра класса, то есть когда мы создаем атрибут с таким же названием внутри класса, то python сразу находит нужный нам атрибут внутри дочернего класса и поэтому не начинает искать в материнском классе на который ссылается этот самый дочерний
@selfedu_rus - its genius 🎉
Вы настолько тонко подметили про "z" attribute, что я тут же пришел в сообщения Вам написать, насколько Вы правы и заметил, что я не один такой 😉
Спасибо, очень интересные, компактные и емкие лекции. 👍🏻
думаю все поняли о чем шла речь.
☮
необычной понятности примеры
Невероятно крут
спасибо огромное
спасибо!👏👍
спасибо
Запрет z спустя 5 месяцев приобретает свой смысл, лайк за видео, как всегда.
Отличный способ запретить Z использовав setattr. Пример как всегда актуальный
Осталось удалить из английского алфавита
Везде надо приплести политику, клоун
@@CAHCrawlAdaptHideПолитика везде, от неё не куда не спрятаться.
Как говорил великий Немчинский, если ты не интересуешься политикой то ты не зрелый человек, вот такие пироги🤷🏻♂️
С первого раза туго пошло, второй раз пересмотрел через пару часов и всё понял. Если что-то не понятно, советую такой подход.
Дуже круто мені понравилось.
Спасибо за ролик! Подскажите, пожалуйста. В примере с помощью переопределения ___getattribute___ вы сделали так, чтобы не было возможности обращаться к атрибуту "x". Правильно понимаю, что на практике правильнее будет сделать переменную "x" приватной, а не использовать переопределение __getattribute__?
И ещё у меня в PyCharm ___getattribute___ вызывается даже если просто написать Point(), то есть, необязательно присваивать переменную для вызова ___getattribute___, это, наверное, потому что у меня более новая версия Python?
Очень интересные и познавательные уроки, спасибо вам!
Только мне кажется, что перед подачей данного материала было бы хорошо людям обьяснить про наследование от object, потому что без понимание этого, тяжело понять материал в этом уроке, что и почему делается.
Спасибо
Спасибо! Про object будет дальше в теме наследование
@@selfedu_rus на данном этапе можно было использовать super() как в прошлом уроке? или так не сработало бы?
Теперь понятно где можно использовать @classmethod 😅
Спасибо Сергею за бан атрибута, с названием Z
Выглядит так, что на посленем слайде, где написано __setattr__(self, key, value)__ - автоматически вызывается при изменении
свойства кеу класса;
два нижних подчеркивания после (self, key, value) лишние. Верно ли это замечание? Или они там нужны?
10:06 Мы бы не хотели что бы создавался атрибут с именем Зет("z") :)
ахахаха
Обидно
хахах, я тож заметил.. потом глянул дату выхода видео - 26 нояб. 2021 г. Он что-то знал ?)))
@@zetmixbeatz почему обидно? Єто знак нацистов и ужасних людей.
@@spraysferry9841 на мой ник взгляни
Возможно вам стоит оставлять номер или ссылки для донатов под видео. Настолько понравились видео, что я бы вам задонатил небольшую сумму. И наверно еще такие люди найдутся :)
спасибо, просто сейчас многие такие сервисы отсеялись, поэтому кроме yoomoney кошелька нечего указывать...
Правильно ли я понимаю, что в видео в местах переопределения магических методов происходит один из принципов ооп - полиморфизм?
👍👍👍👍👍
Благодарю за столь понятное пояснение! Подскажите, в чем разница между Super и object? Когда мы используем метод __new__, мы обращаемся к Super(), а здесь же для __delattr__ (и всех остальных в этом видео) - используем object. Мы ведь и для __new__ тоже можем использовать object?
Спасибо! Разница в том, что super() позволяет обращаться непосредственно к базовому классу (а иерархия наследования может быть самой разной), а через object мы обращаемся к самой вершине иерархии.
@@selfedu_rus
Огромное спасибо!
Такой вопрос, это нужно больше для понимания или же применяется на практике?
урок как всегда супер, все понял, спасибо вам))
Спасибо! На практике это все используется, лучше знать, лишнее я стараюсь не давать.
понемногу становлюсь магом
привет
Благодарю за урок.
Хорошее разъяснение присваивания с self на 2:50.
По примеру метода __setattr__: если удалить строку с "object ...", то в результате выполнения кода всё равно метод вызывается 4 раза. Для чего тогда строка "object ..."?
Строка с "object.__setattr__" обеспечивает непосредственно работоспособность метода. А то, что наблюдается вызов 4 раза, это всего лишь отрабатывает print() внутри этого метода, то есть метод был вызван, но без строки с "object" он никакой работы не выполнил. И чтобы убедиться в этом достаточно вывести все атрибуты после инициализации через pt1.__dict__, например. И попробовать это сделать со строкой "object.__setattr__" и без неё.
Первый, как всегда лайк.
почему при создании экземпляра класса через __new__ мы вызываем super(), а при использовании этих магических методов просто обращаемся к нему как object?
Edit: super() возвращает ссылку на object, а когда пишем object, то напрямую обращаемся? Тогда есть ли разница в этих способах доступа к базовому классу?
Поддерживаю вопрос, тоже интересно
@@beribanyu Как понял я: Если мы используем object, то при return нам нужно указать первым параметром self, а при использовании super это делается автоматически. То есть ,по сути, одно и тоже
👍
10:05 актуальненько))
Мы бы не хотели, чтобы появлялся атрибут "z". Внезапно)
и случайно ))
Тоже вот хотел такое же написать, а оно раз - и есть уже))
С одной стороны, хорошо, что наконец появились видео по этой теме, но с другой стороны как-то обидно, что буквально месяц назад, для одной задачки с кодворс я сам около недели искал информацию по метапрлграммированию и магическим методам, сам разбирался в найденном, при том половина была на английском, а здесь про магические методы рассказывается буквально за пару видео и при этом понятно и информативно
Появляется ощущение, что старания были напрасны(
а можно ли в данном примере с __getattribute__ обращаться к родительскому классу через super().__getattribute__() и если да, то в чём будет отличие от обращения через object.__getattribute__()
При множественном наследовании super() дает непосредственно текущий базовый класс, а не самый базовый object. Во всем остальном без разницы. Метод __getattribute__() можно и так и так вызывать.
Я так понимаю мы "якобы" меняем поведение магического метода но просто вызывая это у object можно сказать что мы засовываем промежуточные команды.
Кстати, ещё вопрос на уточнение. Я правильно понимаю, все классы, которые не наследуются от созданных нами, наследуются от object, у которого метакласс это type?
да, в версии Python3 все классы неявно наследуются от object, если не прописаны какие-либо другие базовые классы и также у всех классов по умолчанию идет метакласс type.
Здравствуйте! Я так понимаю return object.__getattribute__(self, item) и return super().__getattribute__(item) это аналогичные записи?
в целом, да
Почему при вызове магических методов __new__() мы обращались к классу super(), а при вызове этих магических методов обращаемся к классу object
object - это самый базовый класс, а super() возвращает первый базовый класс (на данном уровне object и super() работают одинаково)
@@selfedu_rus спасибо
Можно вопрос тем кто шарит? когда мы переопределяем метод __getattribute__ мы указали object как базовый класс и передали self и item ( object.__getattribute__(self, item) ). Но насколько я понял мы можем также указать вместо object super(). Но когда используешь super() то нужно передавать только item. ( super().__getattribute__(item)). Почему такая разница если мы в и том и в другом случае ссылаемся на родительский класс object ???
очень просто, object - это сам базовый класс, а super() - это объект базового класса, поэтому первый параметр self передается автоматически.
@@selfedu_rusСпасибо за ответ! Правильно ли я понимаю, что использования super() как ссылку на базовый класс для переопределение методов не будет ошибкой? или же правильнее указывать сам базовый класс?
@@user-mk6yf4lu3pлучше super()
@@selfedu_rus Спасибо за объяснения!
спасибо за урок!)
не совсем понимаю как это работает) похоже на то что эти магические методы при создании класса автоматически добавляются без их определения и работают в каком то "режиме по умолчанию"...а когда уже мы их объявляем - мы их работу немного корректируем по своему усмотрению...
либо я не понял как мы после определения метода вызываем тот же метод :
def __getattribute__(self,item):
return object.__getattribute__(self,item):
да, все верно, каждый класс в Python3 наследуется (неявно) от object
@@selfedu_rus а , ну то есть они все в object уже прописаны)) спасибо!)
Почему удаление не происходило при записи del pt1.x ,
а только потом, когда дописали метод
def __delattr__ (self, item):
object.__delattr__(self,item)
?
Ведь по сути этот метод нужен для создания доп действий при удалении какого-то атрибута.
Либо же object.__delattr__(self,item) как раз ставит точку в этой операции удаления(del pt1.x)?
проверил, все удаляет, что то не так сделали, видимо
@@selfedu_rus на 14:14 print(pt1.__dict__) вернул {'x':1, 'y':2}. Пользователь скорее всего спрашивает почему из коллекции __dict__ x удалился только после дописания object.__delattr__(self,item) в метод _delattr_.
Посмотрев ваше видео попробую ответить. Магический метод __delattr__ вызывается при удалении атрибутов экземпляра класса, т.е. происходит только вызов метода. Доп действия вы уже сами придумываете при переопределении магического метода. Так как переопределив мы написали print("__delattr__ :"+item), то при удалении атрибута произойдет только вывод строки. Конкретно логика удаления атрибута происходит в базовом классе object в __delattr__ , именно поэтому необходимо дописать вызов object.__delattr__(self, item) в нашем переопределенном методе __delattr__ класса Point.
Интрересно, что с методом __getattribute__ такой же фокус, как с __setattr__ не прокатывает и:
def __getattribute__(self, item):
print("here is the value:")
return self.__dict__[item]
вызывается рекурсивно. Почему так?
Думаю потому,что __dict__ тоже является атрибутом self. И self.__dict__ [item] по сути является вызовом (получением) атрибута этого экземпляра, что вызывает рекурсию. Но лучше подождать объяснения от автора))
А при использовании __setattr__ хоть мы и изменяем содержимое атрибута __dict__,но не делаем это напрямую, например self.__dict__ = что то, а меняем один из его элементов (некоторый атрибут self'а), и это не считается за изменение атрибута, поэтому рекурсии нет. Опять же, автор лучше знает, я высказал что думаю)
Станут ли задания по ООП на степике когда-нибудь бесплатными ?)
нет
А какая разница между этими магическими методами и дискрипторами?
как часто эти атрибуты используются в реальной работе?
Достаточно часто, что бы знать как пользоваться
Поправьте меня если я не прав, но во второй части напутано, пом меньшей мере в терминологии... 5.25 - здесь в определениях говорится о "свойствах класса", когда в реальности рассказывается об instance variables, а не о class variables, как можно подумать, и как подумает любой, ведь в первой части рассказывалось именно о class variables.
Магические методы __setattr__, __getattribute__, __getattr__ и __delattr__ служат для обработки локальных атрибутов экземпляров классов
8:32
А почему работа с атрибутами private типа не работает примерно так? ( Для примера представим, что у нас в классе
есть два приватных атрибута __x, __y)
Так ведь не выйдет получить доступ, обращаясь к полям
таким образом ._
def __getattribute__(self, item):
if item in ("_Point__x", "_Point__y"):
raise ValueError(f"There no access to item: {item}")
else:
return object.__getattribute__(self, item)
Если вы хотите совсем жестко запретить доступ, то как вариант, но на практике достаточно просто пометить атрибуты как private или protected, чтобы программист знал, что к ним не следует обращаться. Ну а если он нарушит это правило, то работоспособность программы на его совести. Профессионалы так не делают.
@@selfedu_rus Понял, спасибо.
На 6:41 есть ли разница между object.__getattribute__(self, item) и super().__getattribute__(item) ?
Нет, разницы не будет
@@selfedu_rus почему тогда при использовании super().__delattr__(item) возникла ошибка, а при object.__delattr__(self, item) нет?
@@heshagrade Если у вас имеется иерархия наследования, то родительский уже будет не object, т.е. функция-объект super() возвратит другой класс и из-за этого возможны ошибки. Поэтому здесь лучше обращаться через object.
Так получается MIN_CORD в случае когда мы не юзаем classmethod для присвоения ему значения - становиться атрибутом экземпляра класса?
да, т.к. мы используем ссылку на класс
Можете, пожалуйста, подсказать, почему в __setattr__, если присваивать значение атрибуту определенному, открывается рекурсия?
Только что отвечал на это в ТГ-канале. Подписывайтесь на него.
Приоритет вызова дескриптора выше, чем у обычной переменной, поэтому конструкция self.name=name вызывает дескриптор по рекурсии
|__setattr__| вызывается всякий раз при присвоении. Если в нем присвоить значение, то он опять вызовется, опять присвоится, опять вызовется и вот рекурсия
@@Majohne спасибо Вам большое! Теперь я поняла😊
@@selfedu_rus спасибо большое Вам!😊
Почему в __setattr__ не используется return? Опечатка или его особенность?
А зачем Вам что-либо возвращать из этого метода? Вы уже определили новый атрибут через super().__setattr__(...). А если нужно вернуть значение атрибута, то уже непосредственно вызывается метод get
В Украине уже как полтора года запрещены атрибуты Z😁
зачем существует и object и super()? При чём __new__ работает через оба вызова, а __getattribute___ только через вызов object?
похоже что super ссылается просто на родителя, а object к object - самому верхнему классу
Это простые вопросы в ТГ-канал по Python. Сообщество ответит.
сам ответил на свой вопрос )
А почему раньше мы обращались к родительскому классу через super а тут через object? Можно вместо object писать super?
object - это самый верхний (базовый) класс, а super() выдает следующий базовый, от которого мы наследовались. Если наследований явных не было, то super() и object ведут на один и тот же класс.
А почему вызывается именно object?
Все классы в питоне неявно наследуются от object, поэтому и вызывается именно он, т.к. в нем прописаны все эти маг. методы.
Ребзя как долго вы учите Pyhton и что хотите на нем писать???
4 месяца, работать з данными и парсингом
А почему если мы хотим изменить атрибут класса Point, нам просто не написать Point.min_coord = 100 ? вместо целого classmethod ?
чтобы через экземпляр класса менять атрибут класса
Я запутался, понятия "атрибут класса" и "свойство класса" - это синонимы
в общем, да, но чаще СВОЙСТВА я отношу к переменным, а АТРИБУТЫ - ко всем элементам класса (методам, переменным и т.п.)
@@selfedu_rus Хорошо, спасибо
возможно туповатый вопрос, но зачем создавать атрибут, чтобы потом запретить обращаться к нему? 8:20
да, это конечно вопрос вопросов ))) в примере особо им не по пользуешься, просто демонстрация принципа работы не более того
Мы бы не хотели, чтобы появлялся атрибут с именем 'Z'. Очень актуально
😁
вуду-программист)
Если бы в реальной жизни можно было просто взять и написать эксепшен)))
С хрена ли? Этому атрибуту везде дорога.
@@elvin_burunduchock Нет
Всё же до конца не понятно, почему вместо обращения к словарю с атрибутами лучше использовать object.__setattr__()?
метод object.__setattr__() как раз и делает установку атрибутов, поэтому лучше к нему сразу и идти, если прописать super().__setattr__(), то из-за иерархии наследования поиск может идти до object.__setattr__() дольше
@@selfedu_rus это понятно, но я немного о другом.
11:53 почему лучше всего использовать object.__setattr__(self, key, value) вместо self.__dict__[key] = value?
У меня конструкция такая:
for attr in attrs:
self.__dict__[attr].__dict__["new_attr"] = "Default value"
И как в этой конструкции применить __setattr__ не понимаю.
@@VGCor я бы использовал .__setattr__() вместо прямого обращения к __dict__, хотя иногда приходится работать напрямую со словарем (чтобы избежать рекурсии вызовов __setattr__())
а почему вызов через object. а не через super()?
сам и отвечу) погуглил - и так и так можно)
@@x-user-agent Но только если ваш класс не наследуется от другого
Есть тут люди которые проходят и главное понимают все что он снимает ? Как вы это будете применять на практике и ТД
В вакууме, понятное дело, все это лютейшая абстракция. Но если потыкаться самому, сделать хотя бы простенький проект с применением этих штук - очень быстро доходит, как по мне. Ну и еще имеет смысл держать в голове, что ООП раскрывает себя на реально огромных проектах, где находят применение методы из этого видоса, например. Если интерес есть, можешь посмотреть какие-нибудь опенсорс проекты, чтобы увидеть реализацию на практике
И честно, на этом канале обычно самая понятная подача материала, как минимум для меня, из всего, что я смотрел/читал, в том числе и по ООП
Вообще, если прям докапываться, хотелось бы побольше отсылок на примеры из реальных задач, где все это применяется и реализацию, но это такое
Посмотрите фреймворк Django (на этом канале) и увидите, что он без ООП просто немыслим )
Понятно практически все, что Сергей объясняет, но лично я, веду конспект всего материала, иначе информация не удерживается в голове, по крайней мере, у меня. И обязательно закрепляю практикой большую часть материала. Конечно, если просто смотреть, как киношку, то толку 0.
@@KonstantinYurievich Полностью с вами согласен, так же конспектирую в отдельном файле