В какой последовательности в Python вызываются методы __new__ и __init__ при создании объекта?

Ответ

При создании экземпляра класса в Python сначала вызывается статический метод __new__, а затем — метод экземпляра __init__.

  1. __new__(cls, ...)

    • Отвечает за создание и возврат экземпляра класса. Это первый шаг в жизненном цикле объекта.
    • Является статическим методом (первый аргумент — сам класс cls).
    • Должен вернуть экземпляр класса (или его подкласса), иначе __init__ не будет вызван.
    • Используется редко, в основном для реализации паттернов (например, Singleton) или для кастомизации создания неизменяемых (immutable) типов.
  2. __init__(self, ...)

    • Отвечает за инициализацию уже созданного экземпляра. Его задача — установить начальные атрибуты объекта.
    • Является обычным методом экземпляра (первый аргумент — self, ссылка на созданный экземпляр).
    • Ничего не возвращает (точнее, неявно возвращает None).

Пример последовательности вызовов:

class MyClass:
    def __new__(cls, *args, **kwargs):
        print(f"1. Вызов __new__ для класса {cls.__name__}")
        # Создаем экземпляр с помощью __new__ родительского класса
        instance = super().__new__(cls)
        print("   Экземпляр создан")
        return instance

    def __init__(self, value):
        print(f"2. Вызов __init__ для экземпляра {id(self)}")
        self.value = value
        print("   Экземпляр инициализирован")

# При создании объекта вызываются оба метода
obj = MyClass(42)
print(f"nСоздан объект: {obj.value}")

Вывод:

1. Вызов __new__ для класса MyClass
   Экземпляр создан
2. Вызов __init__ для экземпляра 140343833620240
   Экземпляр инициализирован

Создан объект: 42

Ответ 18+ 🔞

А, слушай, вот тебе классика, блядь, про то, как в Питоне объекты на свет появляются. Это ж целая драма в двух актах, ёпта! Сначала, сука, __new__ выходит на сцену, как режиссёр-постановщик, а потом уже __init__ прибегает, как гримёр-костюмер, и начинает этот свежеиспечённый экземпляр разукрашивать.

Так, по порядку, блядь, чтобы не пиздец в мозгах был.

Первый акт, __new__(cls, ...) Этот чувак — статик, ему похуй на конкретные экземпляры пока что. Его задача — взять чертежи класса (cls) и, блядь, создать и вернуть сам объект. Вообще, физически в памяти его слепить. Если он, мудак, ничего не вернёт или вернёт какую-то левую хуйню (не экземпляр этого класса), то второй акт отменяется. __init__ просто не позовут, и всё. Используют его редко, в каких-то извращённых случаях, типа Синглтона, чтобы все на один и тот же объект ссылались, или для immutable типов, где после создания уже нихуя не поменяешь.

Второй акт, __init__(self, ...) А вот этот товарищ уже работает с готовым продуктом. Ему приносят свеженький, только что созданный экземпляр (это и есть self) и говорят: «На, инициализируй, сука!». Он туда атрибуты навешивает, значения устанавливает — короче, обживает. Он нихуя не возвращает, его работа — навести марафет внутри.

Пример, чтобы совсем пиздец понятно стало:

class MyClass:
    def __new__(cls, *args, **kwargs):
        print(f"1. Вызов __new__ для класса {cls.__name__}")
        # Создаем экземпляр с помощью __new__ родительского класса
        instance = super().__new__(cls)
        print("   Экземпляр создан")
        return instance

    def __init__(self, value):
        print(f"2. Вызов __init__ для экземпляра {id(self)}")
        self.value = value
        print("   Экземпляр инициализирован")

# При создании объекта вызываются оба метода
obj = MyClass(42)
print(f"nСоздан объект: {obj.value}")

Что на экране будет, блядь:

1. Вызов __new__ для класса MyClass
   Экземпляр создан
2. Вызов __init__ для экземпляра 140343833620240
   Экземпляр инициализирован

Создан объект: 42

Видишь? Сначала __new__ материализовал эту сущность из ничего, присвоил ей адрес в памяти (этот id). А потом __init__ пришёл, увидел этот адрес и засунул туда значение 42. Вот и вся магия, блядь. __new__ — это про «быть», а __init__ — про «каким быть».