#12. Магический метод __call__. Функторы и классы-декораторы | ООП Python
HTML-код
- Опубликовано: 20 сен 2024
- Курс по Python ООП: stepik.org/a/1...
Разбираем работу магического метода _call_ на конкретных примерах. Узнаете как с его помощью можно заменять замыкания функций и создавать классы-декораторы функций.
Инфо-сайт: proproprogs.ru...
Telegram-канал: t.me/python_se...
Грустно что в школах нет таких учителей, радостно что они есть на ютубе
Я думаю, если бы в школах платили такую же зарплату, что получают только очень хорошие программисты, то Сергей был бы там учителем. А свой собственный курс на степике, был бы неплохой добавкой к этой зарплате.
Сейчас профессию учителя просто втоптали в грязь. А ведь ее важность не меньше, чем у какого-нибудь врача. Врач жизни спасает. А чтобы стать хорошим врачом - надо выучиться. Хреновый учитель, даже будущего гения так отворожит от своего предмета, что тот до конца жизни будет считать себя бездарем в этой теме.
Так вот как реализуются классы декораторы - возился с этой тему,неделю,если не больше,и наконец то понял,спасибо тебе !
Супер)) Спасибо большое, Сергей) ещё бы обещанный Синглтон через __call__ и __new__ и будет счастье)
class MetaSingleton(type):
__instances = None
def __call__(cls, *args, **kwargs):
if cls.__instances is None:
cls.__instances = super().__call__(*args, **kwargs)
return cls.__instances
class Database(metaclass=MetaSingleton):
def __init__(self, user, psw, port):
self.user = user
self.psw = psw
self.port = port
db1 = Database('root', '123456', 80)
db2= Database('root2', '456123', 40)
print(id(db1), id(db2))
print(db1.__dict__)
print(db2.__dict__)
насколько ты красава просто передать не могу) молодец!😎
Лайк, но всё же присоединюсь к тем кого начало трясти от косинусов и синусов, нам бы на яблоках понять Сергей... ))
Урок #12 = Пройден
Спасибо за урок. Пока что понятия не имею, где бы это могло пригодится, но все же, как говорится, лучше знать, чем не знать :)
Сергей,спасибо большое за урок,но заметил такую штуку,что в следующем уроке вы более понятно обьяснили
я посмотрел про str,repr,len,abs,а потом снова посмотрел этот урок и понял))
Все понял, кроме вычисления самой производной)) Пожалуй, надо будет завтра обновить знание, что же это такое.
Здорово! Получается намного компактнее, чем написать параметрический декоратор с кучей вложенных функций
Глубина курса уровня Бог) спасибо за погружение, уже почти нет рыбы, скоро увидим черных курильщиков)
#43. Области видимости переменных. Ключевые слова global и nonlocal | Python для начинающих
ruclips.net/video/TacyWpUF1Kk/видео.html
#44. Замыкания в Python | Python для начинающих
ruclips.net/video/sJF7OMNgLUs/видео.html
#45. Введение в декораторы функций | Python для начинающих
ruclips.net/video/v0qZPplzwUQ/видео.html
#46. Декораторы с параметрами. Сохранение свойств декорируемых функций | Python для начинающих
ruclips.net/video/bl_CnIVpWmQ/видео.html
Тоже сразу вспомнились замыкания
Вот вам для сравнения подхода ООП и функционального.
Замыкание из урока, реализованное на функциях:
def strip_chars(chars):
def stripit(s):
res = s.strip(chars)
return res
return stripit
s1 = strip_chars(chars = '?:!.; ')
s2 = strip_chars(' ')
res = s1(' Hello world! ')
res2 = s2(' Hello world! ')
print(res)
print(res2)
Декоратор на функциях:
def derivate(func):
def wrapper(x, dx=0.0001):
res = (func(x + dx) - func(x)) / dx
return res
return wrapper
@derivate
def df_sin(x):
return math.sin(x)
#df_sin = derivate(df_sin)
print(df_sin(math.pi/3))
Божественно! Огромнейшая вам благодарность!!!!!!
Сергей, спасибо за объяснение! Вы для меня учитель №1 по Питону (его изучаю). Спасибо за все видео!
Вторая часть видео не вызывает вопросов, но от первой немного закипает голова. Прошу прощения если мой вопрос глупый, я всего лишь учусь.
Откуда вызывается метод __call__, если он не определен в классе? Я так понимаю из базового object. Но если мы его переопределим в нашем классе, как у вас показано, то вызывая класс для создания экземпляра, отработает __call__ из класса в котором __new__ нет и соответственно экземпляр не будет создан. Так же Вы говорили, что метод __new__ отработает всегда при создании экземпляра, тогда зачем его вызывать из __call__, как показано у вас в примере?
Бывают глупые вопросы, ответить на которые сложно и долго, поэтому если об этом можно более подробно прочитать, подскажите где, буду признателен.
Да, у вас хороший вопрос. Здесь есть один нюанс. Когда мы определяем метод __call__, то он вызывается только для экземпляров класса, но не для самого класса. Поэтому, когда мы создаем объекты класса, например, pt = Point(), то здесь вызывается __call__ для класса, который определен в метаклассе type (о метаклассах я еще буду рассказывать). Надеюсь, теперь будет понятнее )
@@selfedu_rus спасибо огромное, теперь все предельно понятно.
Спасибо, товарищ Балакирев! лайк
Классы декораторы это круто!
Потрясающе доходчиво
Самое ценное в этом уроке - вспомнил что такое производная). Немного отвлекся, освежил эту, благополучно забытую, математическую тему.
Еще бы уяснить разницу между производной функции и дифферениалом. По мне, сейчас, так это одно и то же.
Огромное спасибо Сергею Михайловичу! Изучаю Python пока в качестве хобби. Пробегаю по быстрому оба курса - начальный и ООП. Знакомлюсь пока, где и что лежит.
90% понятно сразу, потому что очень дельно изложено.
Знаю, что Python это инструмент к математике, на что явно указывают другие курсы Сергея. Вот потом от них и буду возвращаться к языку и досконально вникать в ньюансы.
Еще раз спасибо!!!
Офигеть как годно! Спасибище Сергей!!!
Спасибо, посмотрела!
Спасибо за отличный урок 🫡
Я в перше зробив клас декоратор було інтересно!!! Дуже дякую👍
С Сергеем не только питон выучу , но и геометрию подтяну😄
Супер)) Спасибо большое, Сергей) ещё бы обещанный Синглтон через _call_ и _new_ и будет счастье), самостоятельно я в тупике _ нужна помощь !!!! Тоже очень интересует этот вопрос
Спасибо. Ого! крутизна!
У вас опечатка - "underscoRe" 😉
есть такое )
Вы очень доходчиво объясняете, но без практического примера, как использовать на практике такой метод, ничего не понятно. Т.е. в теории то оно пронятно, но где это тспользовать можно ?
для этого курс на Stepik - ссылка под видео
Спасибо за урок
Может underscore?
Как раз в принципе все функции в питоне - функторы по существу. Чистых функций и переменных в питоне как бы и нет🥴 все объекты, т.е. экземпляры классов
разве это не тоже самое: ";hello world! ".strip("?:!,; ")? причем тут замыкание?
Спасибо!
Сергей, (традиционно) большое спасибо за урок! На 01:30 возник вопрос: как можно переопределить метод `__call__` для класса - и вообще, как программа различает методы `__call__` для класса и для объекта класса, если они выглядят одинаково? И сразу же заодно: я попробовала было отыскать метод `__call__` для класса через `cls.__dict__`, но его там не нашлось. Где он лежит в таком случае?
Спасибо! Все __call__ внутри классов - это для объектов. Если нужен __call__ для класса - это определяется в метаклассе (о них в конце плейлиста). Успехов!
От души!
опечатка небольшая у вас, правильно не underscope, а underscore
да, заметил уже позже, спасибо! )
Нужно дополнительное пояснение, что то совсем запутался я. В момент создания экземпляра класса строкой df_sin = Derivate(df_sin) выполняется функция df_sin, так как аргумент func содержит ссылку на функцию df_sin и присваивает значение - sin(x), приватному атрибуту self.__fn, где x это аргумент принимающий значения = (х + dx) и (x) в строке формулы метода __Call__. Строка print(df_sin(math.pi/3) - запускает магический метод __Call__, где аргумент х получает значение - math.pi/3 и выполняется формула, результат которой, посредством команды return возвращается в функцию print, которая выводит результат на экран. Я все правильно понял?
Зддраствуйте Сергей Балакирев , Наверное вопрос странный но, когда мы вычисляли производную в методе КАЛЛ какое значение выбиралось для х если у него даже начального значения не было по сравнению с dx? И как работает __fn(x+dx) если __fn вычисляет синус на три
def __call__(self, x, dx=0.0001, *args, **kwargs)
второй параметр x - это значение аргумента (точки) в которой берется (вычисляется) производная
Вернувся ставити лайки великій людині)
Декораторы - это как китайский! Но очень интересно! :)))
Подскажите пожалуйста, почему удаление символов (в 1 примере) происходит только в начале и в конце?
Крутий урок- розумієш як писати свої кастомні декоратори-класи
👍
Про удаление символов не очень понятно. Повторила в точности программу - мне пишет "Аргумент должен быть строкой".
👍👍👍👍👍
Что быстрее работает? Есть смысл использовать классы вместо декораторов?
Думаю, разницы в скорости вы здесь не заметите ) А так, что удобнее, то и используйте.
Сергей здраствуйте! Скажите пожалуйста правильно ли я понял: сначала имя df_sin ссылается на объект функции в памяти и у этого объекта счетчик ссылок равен 1. Потом когда функция df_sin декорируется, имя df_sin ссылается на экземпляр класса Derivate. Получается счетчик ссылок уменьшается на 1 и мгновенно увеличивается на 1 за счет того, что атрибут __fn у экземпляра df_sin начинает ссылаться на эту область памяти.
Команда df_sin = Derivate(df_sin) создает объект класса Derivate и внутри объекта сохраняется ссылка на функцию df_sin. Далее, команда df_sin(math.pi/4) вызывает метод __call__ объекта класса Derivate и выполняется то, что записано внутри этого метода. Все, никаких счетчиков! Подробнее - телеграм-канал по Python.
def __call__(self, mul, *args, **kwargs):
def wrapper(x, dx=0.0001, *args, **kwargs):
return (self.func(x + dx) - self.func(x)) / dx * mul
return wrapper
вопрос как в эту конструкцию поступает ссылка на функцию в пайчарме все сработало но если вспомнить функции декораторы, то там мы писали во внешней функции ссылку на функцию в качестве параметра здесь же я не понимаю где ссылка или она автоматически туда попадет при вызове __call__?
В методе call есть ссылка self, функция будет искаться в экземпляре класса, в котором определена функция (funk) через self.funk( ) - self тут основное.
А зачем переопределять метод __call__, если мы можем просто не перезаписывать свойства?
class DataBase:
__instance = None
def __new__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super().__new__(self)
return self.__instance
def __init__(self, user, psw, port):
if not hasattr(self, 'user'):
self.user = user
if not hasattr(self, 'psw'):
self.psw = psw
if not hasattr(self, 'port'):
self.port = port
def __del__(self):
self.__instance = None
db1 = DataBase('root', '123456', 80)
db2 = DataBase('root2', '456123', 40)
print(id(db1), id(db2))
print(db1.__dict__)
print(db2.__dict__)
Получается декораторы на классах менее гибки, потому что на них можно реализовать лишь двойной уровень вложенности. Чаще, как по мне, применяется тройной уровень вложенности. Да и для понимания тройного уровня вложенности не нужно знание ООП, только понимание областей видимости.
на уровне ООП вполне можно делать и декораторы с параметрами, если вы об этом (подробно рассматривается в курсе по ООП на Stepik)
Можно бы попроще объяснять не включая сложные вычисления в код которые отвлекают от сути метода...
Подскажите, если __call__ вызывается в момент создания экз класса, и он вызывает __new__ и __init__, то почему если делать пошагово то увидим , что сначала работает __new__ , затем __init__, и только если мы вызываем сам экземпляр то работает __call__
#12. Магический метод __call__. Функторы и классы-декораторы
#dunder - методы от англ. double underscore
#Магический метод __call__
'''
В действительности, когда происходит вызов класса, то автоматически запускается
магический метод __call__ и в данном случае он создает новый экземпляр этого класса:
'''
"""
c = Counter()
def __call__ (self, *args, **kwargs):
obj = self._new_(self, *args, **kwargs)
self._init_(obj, *args, **kwargs)
return obj
"""
#Функторы - это классы с определённым оператором(). Мы сможем вызвать экз класса
class Counter:
def __init__(self):
print('вызов метода __init__')
self.__counter = 0
def __new__(cls, *args, **kwargs):
print('вызов метода __new__')
return super().__new__(cls)
def __call__(self, step = 1, *args, **kwargs):
print('вызов метода __call__')
self.__counter += step
return self.__counter
c = Counter()
c2 = Counter()
"""Благодаря методу __call__, мы можем вызывать экземпляры класса подобно функции"""
c()
c(2)
res = c(10)
res2 = c2(-5)
print(res, res2)
здесь метод __call__ вызывается у метакласса, а не тот, что объявлен в классе. Когда мы объявляем __call__ в классе, то он вызывается для объектов этого класса (не при создании, а при вызове их подобно функциям).
Привет. Делал сайт по твоим видео, решил добавить функцию "Поделиться статьёй", но я потерпел неудачу. При отправке имейла, через send_mail() после "sock.connect(sa)", вылазит эта зараза "ConnectionRefusedError: [WinError 10061] Подключение не установлено, т.к. конечный компьютер отверг запрос на подключение".Весь интернет перерыл. Я могу тебе задонатить сколько скажешь(в пределал разумного).Буду благодарен невероятно!
Могу попробовать тебе помочь сам. Была такая ошибка у меня
@@mountaindeserver буду очень благодарен. Что от меня нужно?
11:00
"матч"... Хд
примеры нужно брать проще. 2+2 .А синусы косинусы тут ни чему. Потому что надо еще вспоминать что это такое.
Позор тебе, тут теорию гомотопий надо
Спасибо за видео!
Вот только.
Match читается "мэтч", а math - "мэз"!
Согласен. Только это не урок английского. Я готов и к неидеальной дикции и к "русскому" английскому Сергея, т.к. для объяснения теории Питона это не существенно.
@@ValentinKurilyuk
Ну, да.
Поскольку видео про питон, строго запрещено потратить 10 минут и заглянуть в словарь.
Видео посмотрят дети, они буду все это повторять.
Оправдание - оно как ...
не понимаю, зачем было усложнять пример синусами, пи, импортом math ??? очень отвлекает. Результат 0. и 16 цифр ...... нафиг он нужен? какая-то производная. куча слов которые сходу и не вспомнишь. функция должна быть x * 2 или х + 2!!!! вот и хватит. тут главное декораторы понять, а не вспомнить всю математику.
p.s.: а на каком уроке объясняли что значит F7 и F8 ??? не понимаю, почему жмется то ф7, то ф8.
тебе подробный гайд по блокноту тоже записать?
math - мэвс
благодаря вам прохожу стажировку в Aston
Выглядит намного красивее и компактнее, чем обычный вариант с вложенными функциями!
Особенно в случае с декоратором с параметрами, где 3 функции вложены друг в друга