Найти в Дзене
proger ЧАЙНИК

__new__ против __init__ в Python.

Часто __init__ называют конструктором класса, но на самом деле это его инициализатор. Новые объекты класса по-факту создаются методом __new__, который в свою очередь вызывает метод __init__.

Первый аргумент метода __new__cls. Он представляет сам класс, подобно тому, как self представляет экземпляр класса. Это также делает __new__ немного другим видом метода, поскольку он не требует экземпляра класса. И это имеет смысл, поскольку предполагается, что он создает эти экземпляры! Метод возвращает новый экземпляр класса, который затем передается методу __init__.

Обычно нет необходимости самостоятельно определять метод __new__, но он может быть полезен, если мы хотим возвращать инстансы (экземпляры) других классов или ограничивать количество объектов в нашем классе.

Представьте себе, например, что мы хотим создать класс Earth и убедиться, что мы создаем только один объект этого класса. Нам нужно было бы определить переменную класса, которая отслеживала бы количество экземпляров в классе и запрещала бы создание новых, если предел был достигнут.

class Earth:
n = 0
def __new__(cls):
if cls.n == 0: 
          cls.n += 1
return object.__new__(cls) 

Приведенный выше код может быть не сразу понятным, поэтому давайте проанализируем его. Сначала мы проверяем, что переменная класса n имеет нулевое значение. Если это так, это означает, что никакие экземпляры класса не были созданы, и мы можем это сделать. Затем мы обновляем переменную класса и вызываем метод __new__, который позволяет нам создать новый экземпляр. Затем n увеличился и перестал равняться нулю. Поэтому создание следующего нового объекта не получится.

Покажу на примере, после которого станет всё понятно:

earth1 = Earth()
e
arth2 = Earth()

print(
earth1)
>>>  <__main__.Sun object at 0x1106884a8>
print(earth2)  
>>> None