Какова роль и в чем разница между методами __new__ и __init__ в Python

Ответ

Методы __new__ и __init__ — это два ключевых этапа в жизненном цикле создания объекта в Python, но они выполняют принципиально разные задачи.

Ключевое различие: __new__ создает экземпляр, а __init__ его инициализирует (настраивает).

__new__(cls, ...)

  • Роль: Создание (construction) объекта. Отвечает за выделение памяти под новый экземпляр.
  • Вызывается: Первым, до __init__.
  • Тип: Статический метод (хотя и не требует декоратора @staticmethod), первым аргументом принимает класс cls.
  • Возвращаемое значение: Должен вернуть новый экземпляр класса. Если он этого не сделает, __init__ не будет вызван.

__init__(self, ...)

  • Роль: Инициализация (initialization) объекта. Заполняет атрибуты уже созданного экземпляра.
  • Вызывается: Вторым, после __new__.
  • Тип: Метод экземпляра, первым аргументом принимает созданный экземпляр self.
  • Возвращаемое значение: Ничего не возвращает (None).

Пример, демонстрирующий порядок вызова:

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

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

obj = MyClass(10)
print(f"3. Объект создан: {obj.value}")

Вывод:

1. Вызов __new__ для класса MyClass
2. Вызов __init__ для экземпляра 140701234567890
3. Объект создан: 10

Когда использовать __new__?

Переопределение __new__ требуется редко. Основные случаи — реализация паттерна Singleton или создание неизменяемых (immutable) типов, наследуемых от str, int, tuple.