В каких случаях и для чего в Python используется метод __new__?

Ответ

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

Это низкоуровневый метод, который используется редко, но необходим в следующих случаях:

  1. Реализация паттерна Singleton: Гарантирует, что у класса будет только один экземпляр.
  2. Наследование от неизменяемых (immutable) типов: При наследовании от таких типов, как str, int или tuple, необходимо переопределить __new__, так как изменить их после создания уже нельзя.
  3. Создание объектов-заместителей: Когда нужно вернуть экземпляр другого класса в зависимости от переданных аргументов (реализация фабричного метода).

Пример реализации Singleton:

class DatabaseConnection:
    _instance = None

    def __new__(cls, *args, **kwargs):
        # Если экземпляр еще не создан
        if not cls._instance:
            # Создаем новый экземпляр, вызывая __new__ родительского класса
            cls._instance = super().__new__(cls)
        # Возвращаем существующий или только что созданный экземпляр
        return cls._instance

    def __init__(self, dsn):
        # Этот метод будет вызываться каждый раз,
        # но на одном и том же экземпляре.
        self.dsn = dsn

# Оба вызова вернут один и тот же объект
db1 = DatabaseConnection("user:pass@host1")
db2 = DatabaseConnection("user:pass@host2")

print(id(db1) == id(db2))  # Вывод: True
print(db1.dsn)             # Вывод: user:pass@host2

Ключевое отличие от __init__:

  • __new__(cls, ...): Первый аргумент — класс cls. Создает и возвращает экземпляр. Является статическим методом.
  • __init__(self, ...): Первый аргумент — экземпляр self. Ничего не возвращает. Инициализирует уже созданный экземпляр.