Ответ
В Python обязательным первым параметром метода __new__ является cls. Этот параметр представляет собой ссылку на сам класс, для которого создается экземпляр. Он автоматически передается интерпретатором Python при вызове __new__.
Почему cls?
Метод __new__ отвечает за создание и возврат нового экземпляра класса. Поскольку он вызывается до того, как экземпляр будет создан, ему нужна ссылка на класс, чтобы знать, какой тип объекта нужно создать. cls позволяет __new__ вызвать __new__ родительского класса (через super().__new__(cls)) или создать экземпляр другого класса, если это необходимо.
Пример использования __new__:
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
# Создаем экземпляр только если его еще нет
cls._instance = super().__new__(cls)
# Здесь можно выполнить инициализацию, которая должна быть однократной
print("Создан новый экземпляр Singleton")
else:
print("Возвращен существующий экземпляр Singleton")
return cls._instance
def __init__(self, value):
# __init__ вызывается каждый раз, даже для существующего экземпляра
# Поэтому инициализацию, которая должна быть однократной, лучше делать в __new__
if not hasattr(self, '_initialized'): # Проверяем, был ли уже инициализирован
self.value = value
self._initialized = True
print(f"Инициализирован Singleton со значением: {self.value}")
else:
print(f"Singleton уже инициализирован. Текущее значение: {self.value}")
# Демонстрация
s1 = Singleton(10)
s2 = Singleton(20) # __init__ будет вызван, но _instance останется тем же
print(f"s1 is s2: {s1 is s2}")
print(f"s1.value: {s1.value}")
print(f"s2.value: {s2.value}")
Ключевые особенности __new__:
- Вызов до
__init__:__new__вызывается первым и отвечает за создание самого объекта.__init__затем инициализирует этот объект. - Возвращаемое значение:
__new__должен вернуть экземпляр класса (обычноclsили его подкласс). Если__new__не возвращает экземплярcls, то метод__init__для этого экземпляра не будет вызван. - Статический характер: Хотя
__new__является методом класса, он не требует декоратора@classmethodили@staticmethod, так как его поведение как метода класса предопределено интерпретатором Python.