Разница между __init__ и __new__?

__new__ — это статический метод, который создаёт новый экземпляр класса: выделяет память и возвращает объект. __init__ — это метод экземпляра, который инициализирует уже созданный объект: присваивает атрибуты, задаёт начальное состояние. Порядок вызова при создании объекта: сначала __new__, потом __init__.

Подробный ответ

Создание объекта в Python — двухшаговый процесс:

__new__ — «стройка»: создаётся сам объект (экземпляр), выделяется память;

__init__ — «обустройство»: в созданный объект записываются атрибуты и начальные значения.

Аналогия: __new__ строит пустой дом, __init__ расставляет в нём мебель.

Метод __new__ создаёт экземпляр, вызывается до __init__, первым аргументом передается ссылка на класс cls, возвращает новый объект, редко требует переопределения.   

Метод __init__ инициализирует экземпляр, вызывается после __new__, первым аргументом передается ссылка на мозданный объект self, возвращает None, как правило, переопределяется при проектировании класса.

Стандартное использование __init__

В 99% случаев разработчик работает именно с __init__:

class User:
   def __init__(self, name: str, email: str):
       self.name = name
       self.email = email
       
user = User("Alex", "alex@example.com")

__new__ здесь вызывается «молча» под капотом через object.__new__, ты его не видишь.

Когда реально нужен __new__

Переопределять __new__ приходится в нескольких редких, но важных случаях:

1. Наследование от неизменяемых типов (int, str, tuple).

Поскольку их значение задаётся при создании, а не при инициализации, настроить его можно только в __new__:

class EvenInt(int):
   def __new__(cls, value):
       if value % 2 != 0:
           raise ValueError("Only even numbers allowed")
       return super().__new__(cls, value)
EvenInt(4)   # OK
EvenInt(3)   # ValueError

2. Синглтон (один объект на весь класс):

class Singleton:
   _instance = None
   def __new__(cls, *args, **kwargs):
       if cls._instance is None:
           cls._instance = super().__new__(cls)
       return cls._instance

3. Метаклассы и продвинутые паттерны — контроль над инстанцированием классов в целом.

Как ответить на собеседовании?

__new__ создаёт сам объект и возвращает его, __init__ получает уже готовый объект и заполняет его атрибутами. Вызываются они в таком порядке: сначала __new__, потом __init__. В обычных классах переопределяют только __init__, а __new__ нужен в редких случаях: при наследовании от неизменяемых типов вроде int или str, а также при реализации паттерна «синглтон».

Оцени свой прогресс

Честно оцени своё понимание этого вопроса, чтобы мы могли построить твой учебный трек максимально эффективно.
Читать в блоге