python - español - __init__ como constructor?
python__init__ (6)
Sería tentador, pero incorrecto, llamar a esto el constructor de la clase. Es tentador, porque parece que un constructor (por convención,
__init__
es el primer método definido para la clase), actúa como uno (es el primer código ejecutado en una instancia recién creada de la clase) e incluso suena como uno ("Init" ciertamente sugiere una naturaleza constructor-ish). Incorrecto, porque el objeto ya se ha construido para el momento en que se__init__
, y ya tiene una referencia válida para la nueva instancia de la clase.
La cita sugiere que es incorrecto llamar a __init__
como un constructor porque el objeto ya está construido para el momento en que se __init__
. ¡Pero! Siempre he tenido la impresión de que se llama al constructor solo después de que se construye el objeto porque se usa esencialmente para inicializar los miembros de datos de la instancia, lo que no tendría sentido si el objeto no existía cuando se llamó al constructor. ? (procedente del fondo C ++ / Java)
Constructor devuelve una instancia y puede fallar. Pero __init__
no devuelve una instancia. Incluso cuando __init__
plantea y una excepción, se llama a __del__
para eliminar la instancia.
Esto se puede ver aquí:
class A(object):
def __init__(self):
raise ValueError
def __del__(self):
print "Called"
def main():
try:
a = A()
except ValueError, e:
print "ValueError"
if __name__ == ''__main__'':
main()
__new__
por otro lado, devuelve una instancia.
Desde http://www.programiz.com/article/python-self-why
__init__()
no es un constructor[..] Una conclusión importante [..] es que,
__init__()
no es un constructor. Muchos programadores ingenuos de Python se confunden con él ya que__init__()
se llama cuando creamos un objeto. Una inspección más cercana revelará que el primer parámetro en__init__()
es el objeto mismo (el objeto ya existe). La función__init__()
se__init__()
inmediatamente después de que se crea el objeto y se utiliza para inicializarlo.Técnicamente hablando, constructor es un método que crea el objeto en sí mismo. En Python, este método es
__new__()
. Una firma común de este método es
__new__(cls, *args, **kwargs)
Con respecto a la respuesta dada por Ben, yo diría que la mayoría de los idiomas no siguen esa definición (completamente).
Además:
Cuando se
__new__()
, la clase se pasa como el primer argumento automáticamente. Esto es para lo que es lacls
en la firma de arriba. Nuevamente, comoself
,cls
es solo una convención de nombres. Además,*args
y**kwargs
se utilizan para tomar una cantidad arbitraria de argumentos durante las llamadas a métodos en Python.Algunas cosas importantes para recordar al implementar
__new__()
son:
__new__()
siempre se llama antes de__init__()
.- El primer argumento es la clase misma que se pasa de manera implícita.
- Siempre devuelve un objeto válido de
__new__()
. No es obligatorio, pero ese es el punto.
Bottomline (para mí): __new__()
parece ser el constructor, no __init__()
aunque -por todos los medios prácticos __init__()
hace parte de lo que la mayoría de la gente piensa que hará un constructor.
En "Programming Python: Introduction to Computer Science" de John Zelle dice: " El método especial __init__
es el constructor de objetos . Python llama a este método para inicializar un nuevo objeto. El rol de __init__
es proporcionar valores iniciales para las variables de instancia de un objeto."
Personalmente, considero que " __init__
no es un constructor" para ser bastante fino.
__init__
se __init__
cuando se solicita un nuevo objeto. Se supone que debe usar sus argumentos para asignar atributos al nuevo objeto, de modo que se configuren las invariantes requeridas para el funcionamiento normal del objeto. El objeto ya es un lugar preexistente válido para almacenar atributos para cuando el código en __init__
comience a ejecutarse. El nuevo objeto normalmente ya no tiene atributos definidos cuando el código en __init__
comienza a ejecutarse (aparte de los que poseen todos los objetos).
Se llama a un constructor de C ++ cuando se solicita un nuevo objeto. Se supone que debe usar sus argumentos para asignar campos al nuevo objeto, de modo que se configuren las invariantes requeridas para el funcionamiento normal del objeto. El objeto ya es un lugar preexistente válido para almacenar campos en el momento en que el código en el constructor comienza a ejecutarse. El nuevo objeto ya tiene todos sus campos declarados cuando el código en el constructor comienza a ejecutarse, pero contienen basura.
Se llama a un constructor de Java cuando se solicita un nuevo objeto. Se supone que debe usar sus argumentos para asignar campos al nuevo objeto, de modo que se configuren las invariantes requeridas para el funcionamiento normal del objeto. El objeto ya es un lugar preexistente válido para almacenar campos en el momento en que el código en el constructor comienza a ejecutarse. El nuevo objeto ya tiene todos sus campos declarados cuando el código en el constructor comienza a ejecutarse, con sus valores predeterminados.
La principal diferencia entre un método __init__
y un constructor C ++ / Java está en la última frase que he resaltado, y esa es solo la diferencia entre la naturaleza estática de Java / C ++ y la naturaleza dinámica de Python. No creo que esto justifique llamarlos conceptos fundamentalmente diferentes a los que no debe referirse la misma palabra.
Creo que la principal razón por la que a los Pythonistas no les gusta referirse a __init__
como un constructor es que la gente piensa que los constructores C ++ / Java "hacen un nuevo objeto", porque eso es lo que parecen hacer cuando los llamas. Pero realmente hay dos cosas sucediendo cuando llamas a un constructor; se crea un nuevo objeto y luego se llama al constructor para inicializarlo. En C ++ / Java, la parte de "crear un objeto nuevo" es invisible, mientras que se puede exponer / personalizar en Python (a través del método __new__
).
Entonces, aunque el rol del método __init__
es muy similar al rol de un constructor de C ++ / Java, algunas personas prefieren enfatizar el hecho de que este no es todo el proceso al decir que " __init__
no es un constructor".
Si tienes una clase Foo
entonces:
-
Foo()
es el constructor -
Foo.__init__()
es el iniciador -
Foo.__new__()
es el asignador
La construcción de un objeto Python es simplemente la asignación de una nueva instancia seguida de la inicialización de dicha instancia.
__init__
no es un constructor, pero por razones que no le importan a medida que aprende Python. Se comporta de la manera que estás acostumbrado a que los constructores se comporten en C ++ y Java.