Ответ
В 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.
Ответ 18+ 🔞
Так, слушай, а вот этот самый __new__ в питоне, он же, блядь, как заклинание древнее — все знают, что есть, но хуй пойми, зачем. А главный его первый аргумент — cls. Ну, это типа ссылка на сам класс, который мы собираемся создавать. Без этого, сука, интерпретатор просто встанет в ступор: «А чё, блядь, создавать-то? Воздух?»
А нахуя cls?
__new__ — это тот самый пахан, который сначала лепит объект из глины, а уже потом __init__ его раскрашивает. И чтобы слепить, ему надо знать — из какой, сука, глины? Вот cls и говорит: «Вот из этой, епта!» Без него даже super().__new__(cls) не вызовешь — родительский класс не поймёт, какого хуя от него хотят.
Смотри, как это выглядит на практике:
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__и так считается методом класса, не нужно ему никаких@classmethodвешать — питон сам всё понимает, ёпта.