Ответ
В 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.