Вопрос, который я собираюсь задать, кажется дубликатом использования Python __new__ и __init__ ?, но, тем не менее, мне все еще непонятно, в чем практическая разница между __new__
и __init__
.
Прежде чем вы поспешите сказать мне, что __new__
предназначен для создания объектов, а __init__
- для инициализации объектов, позвольте мне пояснить: Я понимаю. На самом деле, это различие вполне естественно для меня, поскольку у меня есть опыт в C ++, где у нас есть новое размещение, которое аналогичным образом отделяет выделение объекта от инициализации.
В руководстве по Python C API это объясняется следующим образом:
Новый член отвечает за создание (в отличие от инициализации) объектов типа. Он представлен в Python как метод
__new__()
. ... Одна из причин для реализации нового метода - обеспечить начальные значения переменных экземпляра.
Итак, да - я понимаю то, что делает __new__
, но, несмотря на это, я все еще не понимаю, почему это полезно в Python. В приведенном примере говорится, что __new__
может быть полезным, если вы хотите «гарантировать начальные значения переменных экземпляра». Ну, разве это не то, что делает __init__
?
В учебнике C API показан пример, в котором создается новый тип (называемый «Noddy») и определяется функция __new__
этого типа. Тип Noddy содержит строковый член с именем first
, и этот строковый член инициализируется пустой строкой, например:
static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
.....
self->first = PyString_FromString("");
if (self->first == NULL)
{
Py_DECREF(self);
return NULL;
}
.....
}
Обратите внимание, что без определенного здесь метода __new__
нам пришлось бы использовать PyType_GenericNew
, который просто инициализирует все члены переменных экземпляра значением NULL. Таким образом, единственным преимуществом метода __new__
является то, что переменная экземпляра будет начинаться с пустой строки, а не с NULL. Но почему это вообще полезно, ведь если бы мы позаботились о том, чтобы переменные нашего экземпляра были инициализированы некоторым значением по умолчанию, мы могли бы просто сделать это в методе __init__
?