La question que je m'apprête à poser semble être une copie de l'utilisation par Python de __new__ et __init__? , mais peu importe, je ne sais toujours pas exactement quelle est la différence pratique entre __new__
et __init__
.
Avant de vous précipiter pour me dire que __new__
c'est pour créer des objets et __init__
c'est pour initialiser des objets, laissez-moi être clair: je comprends cela. En fait, cette distinction est tout à fait naturelle pour moi, car j'ai de l'expérience en C ++ où nous avons un placement nouveau , qui sépare de la même manière l'allocation d'objets de l'initialisation.
Le didacticiel de l'API Python C l' explique comme suit:
Le nouveau membre est responsable de la création (par opposition à l'initialisation) des objets du type. Il est exposé en Python comme
__new__()
méthode. ... Une des raisons d'implémenter une nouvelle méthode est de garantir les valeurs initiales des variables d'instance .
Donc, oui - je comprends ce qui __new__
fait, mais malgré cela, je ne comprends toujours pas pourquoi c'est utile en Python. L'exemple donné dit que cela __new__
peut être utile si vous voulez "garantir les valeurs initiales des variables d'instance". Eh bien, n'est-ce pas exactement ce qui __init__
va faire?
Dans le didacticiel de l'API C, un exemple est montré où un nouveau type (appelé "Noddy") est créé et la __new__
fonction du type est définie. Le type Noddy contient un membre de chaîne appelé first
, et ce membre de chaîne est initialisé à une chaîne vide comme ceci:
static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
.....
self->first = PyString_FromString("");
if (self->first == NULL)
{
Py_DECREF(self);
return NULL;
}
.....
}
Notez que sans la __new__
méthode définie ici, nous devrions utiliser PyType_GenericNew
, qui initialise simplement tous les membres de la variable d'instance à NULL. Ainsi, le seul avantage de la __new__
méthode est que la variable d'instance démarre comme une chaîne vide, par opposition à NULL. Mais pourquoi est-ce toujours utile, puisque si nous voulions nous assurer que nos variables d'instance sont initialisées à une valeur par défaut, nous aurions pu le faire dans la __init__
méthode?
__new__
n'est pas passe-partout, car le passe-partout ne change jamais. Parfois, vous devez remplacer ce code particulier par quelque chose de différent.