La domanda che sto per porre sembra essere un duplicato dell'uso da parte di Python di __new__ e __init__? , ma a prescindere, non mi è ancora chiaro quale sia la differenza pratica tra __new__
e __init__
.
Prima di affrettarti a dirmi che __new__
è per creare oggetti ed __init__
è per inizializzare oggetti, fammi essere chiaro: capisco. In effetti, questa distinzione è abbastanza naturale per me, poiché ho esperienza in C ++ in cui abbiamo un posizionamento nuovo , che separa allo stesso modo l'allocazione degli oggetti dall'inizializzazione.
Il tutorial API Python C lo spiega in questo modo:
Il nuovo membro è responsabile della creazione (anziché dell'inizializzazione) di oggetti del tipo. È esposto in Python come
__new__()
metodo. ... Un motivo per implementare un nuovo metodo è quello di assicurare i valori iniziali delle variabili di istanza .
Quindi, sì - ho capito quello che __new__
fa, ma nonostante questo, io ancora non capisco perché è utile in Python. L'esempio fornito dice che __new__
potrebbe essere utile se si desidera "assicurare i valori iniziali delle variabili di istanza". Bene, non è esattamente quello __init__
che farà?
Nel tutorial dell'API C, viene mostrato un esempio in cui viene creato un nuovo Tipo (chiamato "Noddy") e __new__
viene definita la funzione del Tipo . Il tipo Noddy contiene un membro stringa chiamato first
e questo membro stringa viene inizializzato su una stringa vuota in questo modo:
static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
.....
self->first = PyString_FromString("");
if (self->first == NULL)
{
Py_DECREF(self);
return NULL;
}
.....
}
Si noti che senza il __new__
metodo definito qui, dovremmo usare PyType_GenericNew
, che inizializza semplicemente tutti i membri della variabile di istanza su NULL. Quindi l'unico vantaggio del __new__
metodo è che la variabile di istanza inizierà come una stringa vuota, al contrario di NULL. Ma perché questo è mai utile, dal momento che se ci preoccupassimo di assicurarci che le nostre variabili di istanza fossero inizializzate su un valore predefinito, avremmo potuto farlo nel __init__
metodo?
__new__
non è boilerplate, poiché il boilerplate non cambia mai. A volte è necessario sostituire quel particolare codice con qualcosa di diverso.