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

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

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

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

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

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

__new__

Метод __new__ создаёт экземпляр и вызывается до __init__. Первым аргументом он получает ссылку на класс cls и должен вернуть новый объект. В обычных классах ты его почти никогда не переопределяешь.

__init__

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

В 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 и т.п.) и при реализации паттернов вроде синглтона.

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

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