La pregunta que yo estoy a punto de preguntarle parece ser un duplicado de Python's use of __new__ and __init__?, pero independientemente, aún no está claro para mí exactamente lo que la diferencia práctica entre __new__
y __init__
es.Python (y Python API C): __new__ frente __init__
Antes de salir corriendo a decirme que __new__
es para los objetos que crean y __init__
es para inicializar objetos, quiero ser claro: lo entiendo. De hecho, esa distinción es bastante natural para mí, ya que tengo experiencia en C++ donde tenemos placement new, que separa de manera similar la asignación de objetos de la inicialización.
El Python C API tutorial lo explica de esta manera:
El nuevo miembro es responsable de la creación de (a diferencia de inicialización) objetos del tipo. Está expuesto en Python como el método
__new__()
. ... Una razón para implementar un nuevo método es garantizar los valores iniciales de las variables de instancia .
Así que, sí - me consigo lo __new__
hace, pero a pesar de esto, todavía No entiendo por qué es útil en Python. El ejemplo dado dice que __new__
puede ser útil si quiere "asegurar los valores iniciales de las variables de instancia". Bueno, ¿no es eso exactamente lo que __init__
va a hacer?
En el tutorial C API, se muestra un ejemplo donde se crea un nuevo tipo (llamado "Noddy") y se define la función __new__
del tipo. El tipo Noddy contiene un miembro de cadena llamado first
, y este miembro de la cadena se inicializa a una cadena vacía, así:
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 método __new__
definido aquí, tendríamos que utilizar PyType_GenericNew
, que simplemente inicializa todos los miembros de la variable de instancia a NULL. Entonces, el único beneficio del método __new__
es que la variable de instancia comenzará como una cadena vacía, en oposición a NULL. ¿Pero por qué es esto útil alguna vez, ya que si nos preocupamos de asegurarnos de que nuestras variables de instancia se inicialicen con algún valor predeterminado, podríamos haberlo hecho en el método __init__
?
el código al que se refiere como "repetitivo" en '__new__' no es un texto repetitivo, porque el texto repetitivo nunca cambia. A veces necesitas reemplazar ese código en particular con algo diferente. –
Crear, o adquirir de otra manera, la instancia (generalmente con una llamada 'super') y devolver la instancia son partes necesarias de cualquier implementación' __new__', y la 'repetición' a la que me refiero. Por el contrario, 'pass' es una implementación válida para' __init__' - no se requiere ningún tipo de comportamiento. – ncoghlan