#4. Магический метод __new__. Пример паттерна Singleton | Объектно-ориентированное программирование
HTML-код
- Опубликовано: 19 ноя 2021
- Курс по Python ООП: stepik.org/a/116336
Как работает и зачем нужен магический метод _new_ в Python. Пример его использования при реализации паттерна Singleton.
Плейлист по Python ООП: • Объектно-ориентированн...
Инфо-сайт: proproprogs.ru/python_oop
Telegram-канал: t.me/python_selfedu
видно, что у человека порядок в голове и полное понимание темы. Потому информация, которую он доносит максимально легко усваивается. Спасибо
Подача настолько хороша, что я уже прям чувствую, что скоро начну начинать понимать.
Ты абсолютный гений!!! Какая-то невероятная подача материала!!! Спасибо!!!
ООП становится интересной темой. Огромнейшее спасибо, мне столько в институте не рассказывали сколько я от вас узнала❤🔥❤🔥
Кто ты????? Откуда ты??? Просто пусть у тебя будет так же гладко по жизни как ты даешь материал! Лучший!!!!!!!!!!!
В этом ролкике поначалу было трудно , но после тщательного просмотра несколько раз, до меня ,наконец все дошло , по-моему , один из лучших курсов в СНГ по ООП
Однозначно! Это лучшие видосы по пайтону, но всё равно я другие тоже засматриваюсь, для закрепления темы.
Прекрасные уроки, спасибо!
Очень качественная подача, браво!
Наконец то всё просто и лаконично без взякий дёрганей. Кратко и по факту. Что как создаётся. Почему столь простые вещи так усложняют.
Сергей, спасибо за урок! У вас отличная подача материала.
Отличный курс, спасибо!
Круто..Спасибо большое, важная тема. Подача как всегда на высоте!
Еще раз огромное спасибо! Было бы славно, если бы вы опубликовали код программы в описании для разбора и редактирования.
Отличный канал по урокам на питон, всё понятно, спасибо большое!
Спасибо автору за материалы. Адаптацию практики бы еще под этот новый материал - было бы супер. Да вообще я был бы не против заплатить на каком-нибудь степике за глубокий курс по ООП с хорошими задачами по практике
Так они там вроде есть?
очень крутой урок, огромное спасибо за ваш труд!
Спасибо! Очень интересно и доходчиво! Чувствую как растет моя суперсила))))
Очень полезный материал, я уже год учу пайтон и информация по реализации Singleton очень кстати. Спасибо!
Друже, неистово плюсуюсь к восхищающимся твоей подачей. Очень доходчиво!
Спасибо за очень хорошее объяснение! Мне понравилось очень сильно то, что вы добавили "__del__'!
Мастерски подан материал. Благодарю
Объяснение просто огонь!
Вы объясняете детали, которые у человека маловероятно, что выйдет получить читая книги. Большое Вам спасибо!
Топ! до этого видоса я не до конца понимал суть этого маг метода.
Очень доступно, супер спасибо!!!
ясно-спасибо, действительно подача материала хорошая все остальные ролик выше по запросу непонятно объясняют некоторые моменты
спасибо Вам за материал!
Уроки - моё почтение. 10/10
Спасибо вам большое 🤝
офигенно, еще и с синглтоном! спасибище
Наконец-то поняла, спасибо!❤
Теперь в уроке следующая проблема (Python 3.8.6) ----> при удалении экземпляра класса прописанный служебный метод __del__ не отрабатывает. Те он не меняет атрибут класса. Такое ощущение, что есть какие-то ref'ы к атрибуту именно класса от экземпляра, что препятствует правильному срабатыванию __del__ . Когда атрибут класса является чем либо, но не присваиваемым классом, все отрабатывает на ура, но когда атрибут - сам же класс, то тут начинаются проблемы. Тема с синглтонами весьма неоднозначна и имеет очень много подводных камней.
PS Лайк все-равно поставил)))
Спасибо. Понятно. Вперед!
Молодчинка , лучший !!!
Супер обяснение! Было очень понятно и полезно. Пошел искать видео про магический метод __call__)
Нашел что то?
@@user-mw8qm2nt7f давно) магический метод __call__ делает инстансы(экземпляры) класса вызываемыми(callable), т е. если у нас есть класс MyClass у которого есть метод __call__, то m = MyClass, тут m экземпляр MyClass, и при m() - вызывается метод __call__. Так можно к примеру реализовать декораторы на основе классов. Это если вкратце.
Пс:
Возможно в этом видео это все уже сказано, комментарии мой старый, а видео не пересмотрел)
Конечно, огромный разрыв в понимании в сравнении с предыдущим курсом, хотя.. Может мне только так кажется, учитываю, что я его прошел и сейчас по сути занимаюсь повторением материала? Ну а так, огромное СПАСИБО автору, очень постарался, это прям видно =)
Большое спасибо
Спасибо за ещё одну порцию информации. Дааа... это, конечно, не "ООП за 15 минут"
Спасибо!👏
У меня одного сейчас мозг взорвется? Как было все легко до знакомства с ООП
Не одной, всё нормально
Дорогу осилит идущий!
next django)
Я с ооп уже год топчусь на месте.
Не читайте М. Лутца, он сложно о простом пишет
лайк и коммент в поддержку канала
Спасибо
Прочитала комментарии и хочется сказать - тут зрители аплодируют , апплодируют. Так понятно, что ни йуха не понятно.
Тот случай когда сначала лайк!Почему так мало просмотров?Неужели так мало пайтонистов?
Прочитал все комментарии и не нашлось ответа на вопрос: Если мы удаляем объект через команду del, то классовая переменная по идее должна автоматически None без метода __del__? А если мы не будем вручную удалять объект, а просто присвоем ссылку на другой, то получается в классе будет висеть переменная __instance с сылкой на объект и у нас не будет возможности его удалить командой del?
спасибо
Клевое объяснение
Что значит __перед переменной?
dunder method. Double UDERscore
Это тоже самое что и диез # как ноты lya только при помощи языка lua в том числе UDERscore под double что не патч самого этого method но является еще и классом dunder что под имением super() выводится на главный образ
12:40 Чтобы это поправить нужно просто return засунуть под if
Очень крутое видео, но мозг бум-бум)
радует
Почему бы не запихнуть определение метода init в условный оператор в методе new? Или тогда он не будет автоматически вызываться при создании класса тогда?
Подскажите пожалуйста если в методе __new__ нужно как нибудь проверить параметры, в *args например, после чего создаеться новый обьект с помощью super().__new__(cls) - как их после проверки дальше перенаправить так же в *args далее в __init__ , как правильно прописать синтаксис аля:
super().__new__(cls)(*args, **kwargs)
Вот теперь я понял для чего нужен del xD
А где бы почитать как использовать метод __call__ что бы значения атрибутов, при попытке новой инициализации, не менялись?
Ухх что-то __new__ тяжело заходит, особенно вместе с super)
добрый день. пишу конспект по ооп для собеса. Не подскажете, а правильно ли будет озвучить ответ на вопрос о __new__ в таком виде:
Магический метод __new__ неявно вызывается интерпретатором перед созданием экземпляра класса и возвращает ссылку по которой будет создан объект и далее при помощи конструктора __init__ примет необходимые свойства.
Все очень доходчиво, но неплохо бы про __call__ досказать... Интересно ведь! Спасибо!!!
в уроке №12 досказывает))
можете посоветовать сайт/курс на степике с задачами по практике по ООП?
__super__ !
Примерно на 10 мин. 10 сек. в видео создается метод __del__ в котором значение __instanse вновь приравнивается к None. НО ведь в таком случае мы переопределяем метод __del__, и работать он просто не будет. Мы, как я понимаю, должны были строчкой ниже через super сослаться на нативный __del__ из старшего класса, от которого наследуемся. Или я что-то не понимаю? Спасибо!
Голос похожий на Николя Дроздова из "Мира животных"
Ты сломал моё восприятие уроков этим комментом. Теперь мне всегда кажется, что меня обучает Николай Дроздов
@Сергей Балакирев, а зачем вообще нужно писать финализатор __del__? Ведь он вызывается тогда, когда объект попадает в сборщик мусора, но он никогда туда не попадет, так как атрибут __instance все ровно будет ссылаться на объект, следовательно и счетчик ссылок на объект никогда не будет равен нулю, если только мы вручную не переназначим __instance на другой объект
он реально очень редко прописывается, только если что то нужно сделать с данными при удалении объекта
@@selfedu_rus, а если без него все работает (я прогнал все то же самое без этого метода, результат тот же), для чего его здесь нужно было прописывать, возможно, есть какие-то примеры?
👍👍👍👍👍
Сергей добрый день !
Спасибо за ваш курс!
Подскажите пожалуйста, я столкнулся с вот такой ошибкой в конце данного занятия:
AttributeError: 'DataBase' object has no attribute 'user'
Не могу понять что я делаю не правильно.
Буду вам очень благодарен за помощь!
Работаю в PyCharm
Вот код как на видео:
class DataBase:
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super().__new__(cls)
return cls.__instance
def __del__(self):
DataBase.__instance = None
def __int__(self, user, psw, port):
self.user = user
self.psw = psw
self.port = port
def connect(self):
print(f"соединение с БД: {self.user}, {self.psw}, {self.port}")
def close(self):
print("закрытие соединение с БД")
def read(self):
return "данные из БД"
def write(self, data):
print(f"запись в БД {data}")
db = DataBase('root', '1234', 80)
db2 = DataBase('root2', '5678', 40)
db.connect()
db2.connect()
вы вместо init прописали int ))
@@selfedu_rus стыдоба....😨
@@selfedu_rus спасибо большое !)
даже не понимаю как я такое мог пропустить - много раз перепроверял, а на это даже не обратил ни малейшего внимания.
вот есть некий метод в некотором классе (готовая библиотека из интернета) . и мне нужно выполнить какието свои действия при вызове этого метода ну и потом запустить этот метод(уже из библиотеки) чтобы он свое отработал. но я даже не знаю где его искать и уж тем более как его дополнить чтобы он выполнил мои действия. подскажите плз
Вот пример паттерна Singleton, где свойсва экземпляров сохраняются:
class MetaSingleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Logger(metaclass=MetaSingleton):
def __init__(self, age, jf,):
self.age = age
self.jf = jf
logger1 = Logger('23', 55)
logger2 = Logger('42', 77)
print(logger1, logger2)
print(logger1.__dict__)
print(logger2.__dict__)
Класс!
👍👍
Спасибо, интересно. Подскажите, стоит ли читать Лутца, если уже обладаешь средними знаниями Python?
Не знаю, не читал ))
@@selfedu_rus :)
@@rattlik1 Я тоже таким вопрос задавался) В итоге просто пробежался по оглавлению Лутца. Прочитал пару глав незнакомых и понял, что в принципе можно и без прочтения этой книги обойтись. Но книга действительно неплохая, особенно понравилось, что в конце глав даётся список вопросов, а потом подробные ответы. Не знаю, может быть так во всех книгах сейчас, но например, когда я в школе учился, не видел ни одного учебника, чтобы после теоретических вопросов потом давались ответы на них
@@user-bw4xg8tb9r большое спасибо!
IMHO стоит, особенно по ООП (том2), он там так все подробно объясняет, и по нескольку раз. Книга сама дорогая, но можно раздобыть электронную версию. Даже если ты что-то знаешь никогда не лишне взглянуть с какого-то другого угла, многое заново узнаешь
возможно уже писали, но cls (1:13) ссылается на сам класс(не экземпляр класса, если я не путаю)
В видео так и говорится, там только лишнее слово "экземпляр", нужно просто "класс". Но это из видео понятно совершенно четко.
как получаемые параметры *args и **kwargs методом __new__ передаются далее в __init__? ведь они из __new__ не передаются методу __new__ базового класса .. какой-то __new__ слишком магический метод))
у меня вскипают мозги, но я что то начинаю понимать в отличии от других роликов про ооп где я не понимал ничего
топ
Приветствую! Этот курс будет аналогичен предыдущему по ООП? Не успел тот досмотреть.
Нет, этот больше и глубже
@@selfedu_rus Класс!) Отличный материал!
10:13 подскажите, а можно вместо названия класса (DataBase.__instance = None) указать какую-то переменную, типа cls или super, но тут сдс не подойдет так его нет в области видимости переменных этого метода а super относится к родительскому классу, просто немного похоже на хардкодинг...
Всё, можно не отвечать, ответ есть в следующем видео :)
Получается магич метод __new выполняется сам автоматом при создании экземпляра класса?
да
можешь, пожалуйста, прояснить, в контексте твоего примера: cls.__instance и DataBase.__instance = это тождественные понятия? Если да, то почему по-разному их пишем?
Да, одно и то же. Только cls доступен не во всех методах, а только в классовых (есть еще статик и обычные). Если есть cls - это рекомендуемая практика. В других методах приходится для записи в атрибут класса использовать имя класса.
@@selfedu_rus финализатор __del__, он насколько критичен? Я так понял, что его вводят только для того, чтобы память чистить для быстродействия системы. Типа, если не прописал __del__, ну и ладно, не очень критично для самого выполнения кода
@@vlad161092 да, его редко используют, память чистить не нужно, т.к. Python (сборщик мусора) это делает автоматически
# Реализация Singletona
class Data:
__in = None
def __new__(cls, *args, **kwargs):
if cls.__in == None: # то есть ЭК ещё ни разу не создавался !
cls.__in = super().__new__(cls) # Наследование от базового класса Object, super().__new__(cls)
return cls.__in # А если он уже был, тогда - просто возвращается прежнее super().__new__(cls)
def __init__(self, name = "Cary"): # При создании ЭК ему передаётся один аргумент, или может не передаваться ничего
self.name = name
def get_name(self): # Функция показывает значение атрибута name
print(self.name)
def get_in(self):
print(self.__in)
def set_in(self, inw):
self.__in = inw
d = Data("Coca") # Передаю имя Соса
d.get_name() # Печатаю его
d2 = Data() # Создаю ЭК, не передавая аргумента
d2.get_name() # По умолчанию Cary
Data.get_name(d) # снова выводится Cary
d3 = Data("Gucha") # Создаю ЭК, передаю имя Gucha
Data.get_name(d) # Печатаю name ЭК - d ( a не d3) = Gucha
print(d.__dict__) # Печатаю словарь d {'name': 'Gucha'} - там переопределяется атрибут name
d.get_in() #
d.set_in("jjj") # устанавливаю новое значение свойства __in
d.get_in() # Печатается jjj
d2.get_in() # Печатается jjj
print(d.__dict__, d2.__dict__, d3.__dict__, sep = "
")
# {'name': 'Gucha', '_Data__in': 'jjj'}
# {'name': 'Gucha', '_Data__in': 'jjj'}
# {'name': 'Gucha', '_Data__in': 'jjj'}
print(id(d), id(d2), id(d3), sep = "
")
# 2009777865200
# 2009777865200
# 2009777865200
Как я понимаю курс на степике жители других стран не могут приобрести?
А правильно я понял, ято если в классе не определен метод __new__, то строка pt=Point(1,2) создает экземпляр класса Point, а если определен метод __new__ но в нем нет return, то новый экземпляр класса не создастся.
Создается, только возвращаться не будет )) Ну и, фактически, сборщик мусора его сразу удалит ))
@@selfedu_rus а может, подскажете, как оплатить на Степике этот курс из за границы?
@@maxholon Напишите в ТГ-канал по Python, там попросите кого-либо оплатить, а вы уже ему.
Отличные уроки. Спасибо автору за труд. Но у меня остался вопрос почему в данном примере не работает финализатор __del__? то есть я удаляю db и db2, создаю db3, и id вновь созданного экземпляра остался тот же что был у db и db2.
он отработает, когда сборщик мусора соблаговолит удалить объект, а когда это произойдет никто не знает ))
@@selfedu_rus а если я принудительно пропишу del object_1 а потом создам object_2, почему в таком случае id(object_2) будет таким же как было id(object_1)
@@makooprime насколько я помню программу, там на объект ведет ссылка из класса cls.__instance, а значит, сборщик мусора не уничтожит объект в памяти. При создании нового, просто получите ссылку на уже существующий. Подробнее это можно спросить у сообщества телеграм-канала.
А почему мы не можем просто вместо super() указать object? Ведь super просто - напросто возвращает аллокацию в памяти нашего базового класса object.
P.S. Работает одинаково
Здравствуйте. Скажите, а почему в этом методе def __new...
If cls... is None, a не == None, например..?
Так принято в Python делать проверку на None
@@selfedu_rus , понял. Спасибо!
Красавчик
Здравствуйте! Подскажите, пожалуйста, как можно практиковаться по теме ООП? Нет ли задач, например как на stepic?
Создаю. Будут через месяц-два на степике
@@selfedu_rus Вот это отличные новости! Спасибо!
@@selfedu_rus Доброго времени суток. Когда примерно появится курс?)
@@user-zb4qi5fz4o через месяц точно, возможно раньше, работаю
@@selfedu_rus спасибо, будем ждать)
Все здорово, но у меня возник вопрос: на какой уровень (junior, middle) спрашивают данные вещи?
джун и это база )
на сколько помню __instans нельзя изменить извне? потому что эта переменна закрыта __ вот такими подчеркиваниями?
да, так лучше, согласен
Отличное видео, теперь корректно удаляем. Я бы лишь добавил, что синглтон считается антипаттерном и его следует использовать с осторожностью. Но на таком уровне сложно донести почему это так.
Добрый день у меня вопрос, а зачем в принципе нужен __new__ если в прошлом уроке мы спокойно присваивали новые атрибуты с помощью метода __init__ в строке: "pt = Point(1,2)"
для более тонкого управления созданием объекта, например, паттерн Singleton без new не сделать
__init__ выполняется сразу после создания объекта - создался объект по такому-то адресу, выполнился __init__, который определил заданные в нем параметры.
__new__ вызывается для создания экземпляра класса. По сути, он вызывается всегда из базового (или как еще называют - суперкласса (отсюда и метод super()) класса, при создании экземпляра какого-либо класса. Просто в данном уроке покзано переопределение этого метода внутри класса, чтобы произвести нужные манипуляции до создания его экземпляра.
Т.е. если совсем крато __new__ создает новый экземпляр. __init__ работает с уже созданным с помощью __new__ экеземпляром.
так почему инит не сработал??
Не очень понимаю один момент: создается впечатление, что с помощью __new__ экземпляр создается на базе класса object, а не Point. Или экземпляр автоматически прикрепляется к дочернему классу?
На самом деле экземпляры создаются метаклассом type. Но это уже детали. Достаточно знать, что __new__ срабатывает непосредственно перед созданием объекта.
@@selfedu_rus спасибо:>
👀
спасибо, все понятно. Единственное, как я не пытался так и не смог добиться вызова __del__, ссылка есть всегда и никогда не сбрасывается
это непредсказуемое поведение, но он точно вызывается при удалении объекта из памяти (ее освобождения)
Ссылки на объект класса не всегда явные, и обнаружить их вручную порой затруднительно. Надо пройтись по всем спискам, словарям и т.п. Может где-то объект сравнивается с чем-то. Иногда удаление всех ссылок на объект класса невозможно, пока код выполняется. При прекращении выполнения кода все ссылки удаляться и метод __del__ обязательно отработает. Но иногда это реально доставляет геморрой. Например, есть игра, ну скажем, классический сапёр. Я его написал с помощью pygame. Там есть возможность при проигрыше не запуская заново код, начать новую игру. Естественно, все данные из прошлой игры должны удалиться, что явно и делается. Но остаются неявные ссылки на объект класса Мины, например, которые если удалить, то игра не запуститься заново, вылетит исключение. Так вот, если долго играть, в конце этих объектов накапливается под тысячу, занимая память. Деструктор их не удаляет, так как ссылки на них нужны для правильной работы кода.
возникла ошибка: AttributeError: 'NoneType' object has no attribute 'connect', при попытке использовать db.connect() db2.connect() в чем причина? ведь ранее переданы были атрибуты для экземпляра db = DataBase("root", "1234", 80)
db32 = DataBase("admin", "6677", 40)
должно работать, посмотрите на что ссылаются переменные db (должны на объект класса DataBase
Почему в методе del не super а имя класса? При переименовании классов придётся вносить коррективы?
super() - это обращение к базовому классу; здесь нам нужно менять атрибут текущего класса, поэтому прописывается его имя явно
@@selfedu_rus спасибо за ответ. Как Вы тренируете мозг что он может осознать столько сложной информации? Изучаю Ваши труды - огромное спасибо
у меня абсолютно так же код написан, но инит не вызывается(( в чем может быть косяк?
вот код:
class Point:
def __new__(cls, *args, **kwargs):
print('Вызов __new__ для' + str(cls))
return super().__new__(cls)
def __int__(self, x=0, y=0):
print('Вызов __init__ для' + str(self))
self.x = x
self.y = y
pt = Point(1, 5)
print(pt)
вот что принтуется:
Вызов __new__ для
без инита(
Может быть уже увидели, но у вас название функции __int__ а должно быть __init__ из-за этой опечатки и не работает.
Здравствуйте, очень понравился ваш урок, но есть небольшой вопросик. В методе __new__ для изминения значения __instance, Вы пишите cls.__instance, а в методе __del__ Вы пишите DataВase.__instance. В чем разница между этими двумя записями? Вроде как одно и тоже - все ссылается на класс DataBase... Или как?
в данном случае да, но лучше использовать cls, т.к. имя класса программист может изменить, а в коде забыть поменять
@@selfedu_rus Понял, спасибо!
В методе __new__ cls ссылается на класс, поэтому для изменения значения __instance, пишут cls.__instance. У метода __del__ вместо cls self, а self ссылается на экземпляр класса, а не на сам класс как cls и поэтому, чтобы поменять атрибут класса (!не экземпляра класса) пишут (в нашем случае) DataBase.__instance, а не self. __instance.
@@selfedu_rusа как тогда правильно изменять атрибут класса, если в метод передается только self, как в __init__ или __del__? Ведь через self создастся новая переменная у экземпляра с таким же именем, а не изменится атрибут класса. Использовать type(self)?
@@veahcen либо прописывать имя класса перед атрибутом (вместо self), либо (и чаще всего) создается метод класса (classmethod) и у него вместо self идет cls - ссылка на сам класс
Не понял что изменилось, вроде тот же урок
Была ошибка при реализации паттерна Singleton, поправил
блеск
Магия и бесовщина этот ваш питон. Но спасибо за разъяснения!
Чуть не понял,в определении __new__ указывается что он создается перед самим объектом класса,но как ты тогда в него переменную instance вводишь,если new создается до всего,еще ты вроде не уточнил что блок __new__ начинает работать именно в экземплярах класса,как по мне это не очень очевидно.
1. cls.__instance - это обращение к атрибуту класса, а не создаваемого экземпляра, т.к. экземпляра еще нет.
2. метод new выполняется как классовый метод, а не метод экземпляра.
@@selfedu_rus Ты чуть не правильно меня понял,ты упоминал что перед созданием каласа вызывается __new__ то есть класса и его переменных не существует,то как тогда ты в эту функцию __new__ передаешь instance ,ведь это переменная класса
@@origami5334 перед созданием экземпляра класса, если сказал просто класса, то оговорился