¿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.