Ответ
__new__ и __init__ — это два специальных метода, участвующих в создании экземпляра класса, но они выполняют принципиально разные задачи в процессе инстанцирования.
| Метод | Когда вызывается | Задача | Возвращаемое значение | Аналог в других языках |
|---|---|---|---|---|
__new__(cls, ...) |
Первым, в момент создания объекта. | Создать и вернуть новый экземпляр (объект). Это конструктор на уровне класса. Управляет самим процессом выделения памяти. | Должен вернуть новый экземпляр (обычно super().__new__(cls)). Может вернуть объект другого типа. |
Конструктор (new в C#, Java). |
__init__(self, ...) |
Вторым, после __new__, если __new__ вернул экземпляр этого же класса. |
Инициализировать (настроить) созданный объект. Устанавливает начальные значения атрибутов. Это инициализатор. | Ничего не возвращает (None). Изменяет переданный ему объект self. |
Инициализатор (метод __init__ или конструктор с установкой полей). |
Простая аналогия:
__new__— это производство пустого автомобиля на заводе.__init__— это комплектация этого автомобиля: покраска, установка сидений и руля.
Базовый пример последовательности вызовов:
class MyClass:
def __new__(cls, *args, **kwargs):
print(f"__new__ called. Creating instance of {cls.__name__}")
# 1. Создаем экземпляр. Обычно это делает object.__new__
instance = super().__new__(cls)
return instance # Этот объект будет передан в __init__ как `self`
def __init__(self, value):
print(f"__init__ called. Initializing with value={value}")
self.value = value
obj = MyClass(42)
# Вывод:
# __new__ called. Creating instance of MyClass
# __init__ called. Initializing with value=42
Практическое применение __new__ (когда он нужен):
__new__ используется редко, в основном для нетривиального управления созданием объектов:
- Создание неизменяемых (immutable) типов: Так как
__init__может изменить объект, для неизменяемых классов (наследниковtuple,int) логику установки значений нужно поместить в__new__. -
Паттерн Singleton (ограничение числа экземпляров):
class Singleton: _instance = None def __new__(cls): if cls._instance is None: print("Creating the single instance") cls._instance = super().__new__(cls) return cls._instance # Всегда возвращаем один и тот же объект def __init__(self): # Внимание: __init__ будет вызываться каждый раз при вызове Singleton()! print("Singleton __init__ called")
s1 = Singleton() # Создаст экземпляр, вызовет init s2 = Singleton() # Вернет существующий экземпляр, но init вызовется снова! print(s1 is s2) # True
**Важное замечание:** В Python `__init__` вызывается автоматически, если `__new__` вернул объект того же класса. Это может привести к неочевидному повторному вызову `__init__` для уже инициализированного объекта (как в Singleton выше). Поэтому `__new__` и `__init__` нужно использовать согласованно. Ответ 18+ 🔞
А, слушай, вот тебе история, которая многих вводит в ступор, как будто они впервые видят два одинаковых ключа от разных замков. Речь про __new__ и __init__. Это, блядь, основа основ, но люди их постоянно путают, а потом удивление пиздец — почему код работает как кот, сука, собака.
Представь себе такую картину. Ты приходишь на стройку. __new__ — это прораб, который получает чертёж (это класс, cls) и говорит: «Так, мужики, нам нужна одна хатка. Делаем фундамент, стены, крышу — вот вам готовая коробка». Он создаёт сам объект из ничего, как бог из глины. Это конструктор в чистом виде, он возвращает эту самую новую коробку-объект.
А потом в работу вступает __init__. Это уже дизайнер-отделочник. Он приходит в готовую пустую коробку (это self) и начинает там всё обустраивать: «Сюда диван, тут телевизор повесим, а на стену — фотку тёщи, чтобы пугаться». Он ничего не возвращает, он просто настраивает то, что ему передали.
Вот тебе живой пример, чтобы совсем мозг не взорвался:
class MyClass:
def __new__(cls, *args, **kwargs):
print(f"Ёпта, вызываю __new__. Создаю экземпляр для {cls.__name__}")
# Всё, мужики, главная магия тут. Просим у базового object создать объект.
instance = super().__new__(cls)
return instance # Возвращаем голую заготовку
def __init__(self, value):
print(f"А теперь __init__! Настраиваю объект, value={value}")
self.value = value # Вешаем табличку с номером
obj = MyClass(42)
# Выведет:
# Ёпта, вызываю __new__. Создаю экземпляр для MyClass
# А теперь __init__! Настраиваю объект, value=42
Видишь порядок? Сначала __new__ делает объект, потом __init__ его начиняет. Без первого — второго просто не будет, потому что инициализировать нечего, чистая пустота.
А зачем вообще этот __new__, если __init__ всегда был в деле?
Вот тут начинается самое интересное. Обычному смертному в __new__ лезть не надо, но есть моменты, когда без него — просто никуда, ёперный театр.
- Неизменяемые типы (immutable). Представь, ты делаешь свой собственный аналог кортежа. В
__init__ты уже не можешь поменять внутренности объекта, потому что он якобы неизменяемый. Вся логика по «упаковке» данных должна произойти в момент создания. Поэтому__new__— твой единственный друг. - Паттерн Singleton (когда нужен один экземпляр на весь мир). Классика жанра, где
__new__становится хитрой жопой.
class Singleton:
_instance = None # Здесь будем хранить нашу одну-единственную копию
def __new__(cls):
if cls._instance is None:
print("Создаю единственный экземпляр, бля!")
cls._instance = super().__new__(cls)
# А вот тут внимание, ядрёна вошь! Мы ВСЕГДА возвращаем один и тот же объект.
return cls._instance
def __init__(self):
# ВАЖНОЕ ПРЕДУПРЕЖДЕНИЕ! __init__ будет вызываться КАЖДЫЙ РАЗ, когда ты пишешь Singleton()!
print("Singleton __init__ called. Может быть много раз, осторожно!")
s1 = Singleton() # Создаст объект и вызовет __init__
s2 = Singleton() # Вернёт старый объект, но __init__ вызовется снова!
print(s1 is s2) # Выведет True, потому что это один и тот же объект в памяти.
Видишь подвох? __init__ отрабатывает при каждом вызове Singleton(), даже если объект старый. Поэтому с такими паттернами надо быть осторожным, а то доверия ебать ноль к такому коду будет.
Итог простой, как три копейки:
__new__(cls, ...)— волшебник, который материализует объект из воздуха. Вызывается первым, должен вернуть этот объект.__init__(self, ...)— хозяйственник, который обживает готовую квартиру. Вызывается вторым (если__new__вернул объект этого класса), ничего не возвращает, только настраиваетself.
Запоминай так: __new__ — это «что создать», __init__ — это «как инициализировать». Перепутаешь — получишь TypeError и полное недоумение, какого хуя ничего не работает.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶