Рассмотрим простой тестовый пример, чтобы разобраться с порядком вызова функций:
class Test:
def __call__(self, *args, **kwargs):
print(f'__call__ called with value {self.value}')
def __new__(cls, *args, **kwargs):
print('__new__ called')
return object.__new__(Test)
def __init__(self):
self.value = '999'
print('__init__ called')
t = Test()
print('some string printed')
t()
Вывод:
__new__ called
__init__ called
some string printed
__call__ called with value 999
При создании экземпляра класса, первым делом вызывается функция __new__
. Ее задача - вернуть пустой объект, для которого мы и создадим все нужные поля.
После этого вызывается функция __init__
(Этот момент я попрошу запомнить, почему так происходит я расскажу чуть позже). Ее задача - задать все необходимые поля для объекта, который нам вернула функция __new__
.
Теперь объект создан и мы можем с ним работать. Печатаем какую-нибудь строку.
И теперь при вызове t()
. Будет вызвана функция __call__
. Она НЕ участвует в создании объекта и вызывается при попытке обратиться к уже созданному объекту, как к функции (со скобочками). (О том, где вы могли слышать про call в создании объекта я тоже расскажу чуть ниже)
Теперь предлагаю посмотреть на выжимку из исходного кода CPython (находится здесь):
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj;
PyThreadState *tstate = _PyThreadState_GET();
if (type == &PyType_Type) {
assert(args != NULL && PyTuple_Check(args));
assert(kwds == NULL || PyDict_Check(kwds));
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
if (nargs == 1 && (kwds == NULL || !PyDict_GET_SIZE(kwds))) {
obj = (PyObject *) Py_TYPE(PyTuple_GET_ITEM(args, 0));
return Py_NewRef(obj);
}
if (nargs != 3) {
PyErr_SetString(PyExc_TypeError,
"type() takes 1 or 3 arguments");
return NULL;
}
}
if (type->tp_new == NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"cannot create '%s' instances", type->tp_name);
return NULL;
}
obj = type->tp_new(type, args, kwds);
obj = _Py_CheckFunctionResult(tstate, (PyObject*)type, obj, NULL);
if (obj == NULL)
return NULL;
if (!PyObject_TypeCheck(obj, type))
return obj;
type = Py_TYPE(obj);
if (type->tp_init != NULL) {
int res = type->tp_init(obj, args, kwds);
if (res < 0) {
assert(_PyErr_Occurred(tstate));
Py_SETREF(obj, NULL);
}
else {
assert(!_PyErr_Occurred(tstate));
}
}
return obj;
}
Возможно здесь не всё понятно сразу, особенно если вы никогда не писали на чистом Си, но здесь представлен основной код реализации метода __call__
у встроенного класса type
. Именно он и вызывается, когда вы вызываете t=Test()
Например, вместо вызова как сверху, вы можете создать объект с аналогичным поведением вот так:
t = type.__call__(Test)
При этом порядок вывода не изменится.
Как мы выяснили, вызов __new__
происходит при вызове __call__
у type
, который неявно вызывается при создании объекта.
Внутри питона (то бишь в исходниках на Cи) выделяется память под новый объект, который мы получаем из функции __new__
, которую мы переопределяем в нашем классе. После этого, на моменте int res = type->tp_init(obj, args, kwds);
вызывается функция __init__
, которая инициализирует наш объект (устанавливает поля и т.д.)
И вот этот полученный объект нам и возвращается в переменную t
, которую мы объявили в питоне.
Кстати, если посмотреть в исходники, можно заметить проверку:
if (!PyObject_TypeCheck(obj, type))
return obj;
Эта проверка происходит до момента вызова tp_init
(то бишь питоновской функции __init__
)
Как не трудно догадаться, проверяет она соответствие полученного объекта классу, для которого мы его создавали. Что это значит? Что если из функции __new__
мы вернем объект, не являющийся экземпляром нашего класса, то __init__
вызываться не будет. Например:
class Other:
def __init__(self):
print('other __init__ called')
def __new__(cls, *args, **kwargs):
print('other __new__ called')
return super().__new__(cls, *args, **kwargs)
def __call__(self, *args, **kwargs):
print('other __call__ called')
class Test:
def __call__(self, *args, **kwargs):
print(f'__call__ called with value {self.value}')
def __new__(cls, *args, **kwargs):
print('__new__ called')
return Other()
def __init__(self):
self.value = '999'
print('__init__ called')
t = Test()
Вывод будет:
__new__ called
other __new__ called
other __init__ called
Здесь при создании объекта вызвалась функция __new__
из класса Test
. В ней из нее мы вернули экземпляр класса Other
. При его создании вызвалась other __new__
. И после этого вызывалась other __init__
. Основной __init__
(из класса Test
) Так и не вызвался. Заметьте, что __init__
класса Other
был вызван, потому что из функции __new__
класса Other
мы возвращаем super().__new__(cls, *args, **kwargs)
. То есть возвращаем то, что нам вернет функция __new__
, определенная у родителя (родителем по умолчанию будет класс object
). И именно object.__new__
и вызывается, если ваш класс не переопределяет функцию __new__
.
Эксперимент: Попробуйте в классе Other
из __new__
вернуть пустой объект object()
. Тогда вы увидите, что other __init__
тоже не будет вызван.
Кстати, никто не запрещает вызывать __init__
напрямую из __new__
, например вот так:
class Other:
def __init__(self):
print('other __init__ called')
def __new__(cls, *args, **kwargs):
print('other __new__ called')
return super().__new__(cls, *args, **kwargs)
def __call__(self, *args, **kwargs):
print('other __call__ called')
class Test:
def __call__(self, *args, **kwargs):
print(f'__call__ called with value {self.value}')
def __new__(cls, *args, **kwargs):
print('__new__ called')
obj = Other()
cls.__init__(obj)
return obj
def __init__(self):
self.value = '999'
print('__init__ called')
t = Test()
#print('some string printed')
t()
Вывод:
__new__ called
other __new__ called
other __init__ called
__init__ called
other __call__ called
Как видно, здесь Test.__init__
был вызван, но при попытке вызова t()
, запускается функция из класса Other
. Потому что именно объект класса Other мы вернули из Test.__new__
.
print(type(t)) # <class '__main__.Other'>
Итак. Подведем итог:
При создании экземпляра класса:
Вызывается Test.__new__
. Которая возвращает объект.
После этого (если __new__
вернула объект типа Test или его наследника) вызывается Test.__init__
, устанавливающий все нужные поля и т.д.
Когда стоит переопределять __new__
, а когда __init__
?
Простой ответ:
в 99.9% случаев стоит переопределять __init__
Сложный ответ:
__new__
стоит переопределять, когда при создании экземпляра класса может быть необходима какая-то логика связанная с тем, будет ли вообще по итогу создан новый объект, или нет. Например: Если при создании нового объекта нам нужно следить за количеством уже созданных экземпляров и т.п.
__init__
же стоит переопределять тогда, когда при создании объекты мы хотим задать этому объекту какие-то поля, вызвать какие-то внешние функции (например напечатать что-то и т.п.), которые не затрагивают информацию о других созданных экземплярах класса и т.п. (Практически всегда)