Вопрос, который я собираюсь задать, похоже, повторяет использование Python __new__ и __init__? , но, тем не менее, мне все еще неясно, в чем практическая разница между __new__
и __init__
.
Прежде чем вы поспешите сказать мне, что __new__
это предназначено для создания объектов и __init__
для инициализации объектов, позвольте мне пояснить: я понимаю. Фактически, это различие вполне естественно для меня, поскольку у меня есть опыт работы с C ++, где у нас есть размещение new , которое аналогичным образом отделяет выделение объекта от инициализации.
В руководстве по 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__
методе?
__new__
не является шаблонным, потому что шаблон никогда не изменяется. Иногда вам нужно заменить этот конкретный код чем-то другим.