Ответ
Да, метод __new__ в Python позволяет контролировать процесс создания экземпляра. В отличие от __init__, который инициализирует уже созданный объект, __new__ его создает и возвращает.
Чтобы отменить или изменить создание, __new__ может вернуть:
- Существующий экземпляр: Это основной механизм для реализации паттерна Singleton.
- Экземпляр другого класса: Можно перенаправить создание на другой класс.
None: Технически возможно, но это приведет к ошибкеTypeError, так как последующий вызов__init__получитNoneвместо ожидаемого экземпляра.
Важно: Метод __init__ вызывается только в том случае, если __new__ возвращает экземпляр того же класса (cls).
Пример (Singleton):
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
# Если экземпляр еще не создан
if cls._instance is None:
print("Создание нового экземпляра")
# Создаем его с помощью родительского __new__
cls._instance = super().__new__(cls)
else:
print("Возврат существующего экземпляра")
# Всегда возвращаем единственный экземпляр
return cls._instance
def __init__(self):
# Этот код будет выполняться при каждом вызове Singleton(),
# даже если возвращается старый экземпляр.
print("Вызов __init__")
s1 = Singleton()
# Вывод:
# Создание нового экземпляра
# Вызов __init__
s2 = Singleton()
# Вывод:
# Возврат существующего экземпляра
# Вызов __init__
print(s1 is s2) # True Ответ 18+ 🔞
Слушай, а вот этот ваш __new__ в Python — это вообще магия какая-то, блядь! Ну, типа, все знают про __init__, который как бы «инициализирует» объект, а этот гадёныш __new__ — он его вообще создаёт, сука, с нуля! И может такое вытворять, что мама не горюй.
Вот смотри, если совсем по-простому: __new__ может вернуть тебе три варианта, и от этого зависит, будет ли вообще объект или нет.
- Вернуть уже существующий объект. Это классика, блядь, для этих ваших синглтонов, когда нужно, чтобы класс был один, как перст, на весь проект. Хули плодить сущности?
- Вернуть объект другого класса. Ну, подменил, сука, как в детстве конфету на камушек. Запросили
MyClass, а получилиOtherClass. Сюрприз, пиздец! - Вернуть
None. Ну, это уже совсем жесть. Технически можно, но потом__init__получит в руки этотNoneи обосрётся с ошибкойTypeError. Так что не рекомендую, если только специально не хотите всё сломать, блядь.
И главное, запомни, ёпта: __init__ вызовется только если __new__ вернул объект ТОГО ЖЕ самого класса (cls). Если вернул что-то другое — иди нахуй со своей инициализацией, её не будет.
Вот, смотри пример, как сделать эту самую «одиночку» (Singleton), чтобы все твои вызовы класса возвращали один и тот же объект, а не плодили клонов, как сука тараканов:
class Singleton:
_instance = None # Тут будем хранить наш единственный экземпляр, блядь
def __new__(cls, *args, **kwargs):
# Если экземпляра ещё нет — создаём
if cls._instance is None:
print("Создание нового экземпляра")
# Вот тут магия: вызываем __new__ у родительского класса (обычно object)
cls._instance = super().__new__(cls)
else:
print("Возврат существующего экземпляра")
# И всегда, сука, всегда возвращаем один и тот же объект
return cls._instance
def __init__(self):
# Внимание! Этот __init__ будет вызываться КАЖДЫЙ РАЗ, когда ты пишешь Singleton(),
# даже если объект старый. Так что тут осторожнее, а то наинациализируешься.
print("Вызов __init__")
# Пробуем
s1 = Singleton()
# Вывод:
# Создание нового экземпляра
# Вызов __init__
s2 = Singleton()
# Вывод:
# Возврат существующего экземпляра
# Вызов __init__
print(s1 is s2) # True, блядь! Это один и тот же объект!
Вот и вся магия, ёпта. __new__ — это как прораб на стройке объекта: он решает, строить новый дом или выдать ключи от уже готового. А __init__ — это уже дизайнер интерьеров, которого пускают внутрь, только если прораб сказал «да».