¿La pregunta que estoy por hacer parece ser un duplicado del uso que hace Python de __new__ y __init__? , pero independientemente, todavía no me queda claro cuál es la diferencia práctica entre __new__y __init__.
Antes de que te apresures a decirme eso __new__ es para crear objetos y __init__para inicializar objetos, déjame ser claro: lo entiendo. De hecho, esa distinción es bastante natural para mí, ya que tengo experiencia en C ++ donde tenemos una ubicación nueva , que separa de manera similar la asignación de objetos de la inicialización.
El tutorial de Python C API lo explica así:
El nuevo miembro es responsable de crear (en lugar de inicializar) objetos del tipo. Está expuesto en Python como
__new__()método. ... Una razón para implementar un nuevo método es asegurar los valores iniciales de las variables de instancia .
Entonces, sí, entiendo lo que __new__hace, pero a pesar de esto, yo todavía no entiendo por qué es útil en Python. El ejemplo dado dice que __new__podría ser útil si desea "asegurar los valores iniciales de las variables de instancia". Bueno, ¿no es eso exactamente lo __init__que hará?
En el tutorial de la API de C, se muestra un ejemplo donde se crea un nuevo Tipo (llamado "Noddy"), y el Tipo __new__ se define función . El tipo Noddy contiene un miembro de cadena llamado first, y este miembro de cadena se inicializa en una cadena vacía de la siguiente manera:
static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
.....
self->first = PyString_FromString("");
if (self->first == NULL)
{
Py_DECREF(self);
return NULL;
}
.....
}
Tenga en cuenta que sin el __new__método definido aquí, tendríamos que usar PyType_GenericNew, que simplemente inicializa todos los miembros de la variable de instancia a NULL. Entonces, el único beneficio del __new__método es que la variable de instancia comenzará como una cadena vacía, en lugar de NULL. Pero, ¿por qué es esto útil, ya que si nos preocupamos por asegurarnos de que nuestras variables de instancia se inicialicen con algún valor predeterminado, podríamos haberlo hecho en el __init__método?
__new__no es boilerplate, porque boilerplate nunca cambia. A veces necesita reemplazar ese código en particular con algo diferente.