В чем разница между методами __new__ и __init__ в Python?

Ответ

__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__ используется редко, в основном для нетривиального управления созданием объектов:

  1. Создание неизменяемых (immutable) типов: Так как __init__ может изменить объект, для неизменяемых классов (наследников tuple, int) логику установки значений нужно поместить в __new__.
  2. Паттерн 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__ лезть не надо, но есть моменты, когда без него — просто никуда, ёперный театр.

  1. Неизменяемые типы (immutable). Представь, ты делаешь свой собственный аналог кортежа. В __init__ ты уже не можешь поменять внутренности объекта, потому что он якобы неизменяемый. Вся логика по «упаковке» данных должна произойти в момент создания. Поэтому __new__ — твой единственный друг.
  2. Паттерн 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 и полное недоумение, какого хуя ничего не работает.