A pergunta que estou prestes a fazer parece ser uma duplicata do uso de __new__ e __init__ pelo Python? , mas, independentemente disso, ainda não está claro para mim exatamente qual é a diferença prática entre __new__
e __init__
é.
Antes de você se apressar para me dizer que __new__
é para criar objetos e __init__
para inicializar objetos, deixe-me esclarecer: entendi. De fato, essa distinção é bastante natural para mim, já que tenho experiência em C ++, onde temos um novo posicionamento , que também separa a alocação de objetos da inicialização.
O tutorial da API do Python C explica assim:
O novo membro é responsável por criar (em vez de inicializar) objetos do tipo. É exposto no Python como o
__new__()
método. ... Um motivo para implementar um novo método é garantir os valores iniciais das variáveis da instância .
Então, sim - eu entendo o que __new__
faz, mas, apesar disso, ainda não entendo por que é útil no Python. O exemplo dado diz que __new__
pode ser útil se você deseja "garantir os valores iniciais das variáveis da instância". Bem, não é exatamente isso que __init__
fará?
No tutorial da API C, é mostrado um exemplo em que um novo Type (chamado "Noddy") é criado e a __new__
função do Type é definida. O tipo Noddy contém um membro da cadeia de caracteres chamado first
e esse membro da cadeia é inicializado em uma cadeia vazia da seguinte forma:
static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
.....
self->first = PyString_FromString("");
if (self->first == NULL)
{
Py_DECREF(self);
return NULL;
}
.....
}
Observe que, sem o __new__
método definido aqui, teríamos que usar PyType_GenericNew
, que simplesmente inicializa todos os membros da variável de instância para NULL. Portanto, o único benefício do __new__
método é que a variável de instância começará como uma sequência vazia, em oposição a NULL. Mas por que isso é útil, pois se nos importamos em garantir que nossas variáveis de instância sejam inicializadas com algum valor padrão, poderíamos ter feito isso no __init__
método?
__new__
não é clichê, porque o clichê nunca muda. Às vezes, você precisa substituir esse código específico por algo diferente.