Constructores de Python y __init__

107

¿Por qué los constructores se llaman "Constructores"? ¿Cuál es su propósito y en qué se diferencian de los métodos de una clase?

Además, ¿puede haber más de uno __init__en una clase? Intenté lo siguiente, ¿alguien puede explicar el resultado?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

Finalmente, ¿es __init__un operador overloader?

Arindam Roychowdhury
fuente
41
Técnicamente, __init__es un inicializador . El constructor de Python es __new__. Python usa la inicialización automática de dos fases: __new__devuelve un objeto válido pero (generalmente) no poblado (ver boolun contraejemplo), que luego lo ha __init__llamado automáticamente. Esto evita los problemas que tienen los lenguajes como C ++ con los objetos parcialmente construidos; nunca tiene uno en Python (aunque puede estar parcialmente inicializado). Casi nunca necesitará anular ambos __new__y __init__en una clase.
Tim Delaney
2
@TimDelaney: No estoy seguro de a qué te refieres con objetos parcialmente construidos en C ++.
Sebastian Mach
11
@phresnel En C ++ el tipo de objeto es la clase base (no la subclase) mientras que en el constructor de la clase base. No puede llamar a un método virtual en el constructor de la clase base y hacer que la subclase proporcione la implementación. En Java, puede llamar a un método de subclase en el constructor de la clase base, pero las variables del miembro de la subclase se inicializarán automáticamente después del constructor de la clase base (y la llamada al método). En lenguajes con inicialización de dos fases como Python, puede llamar felizmente a métodos en el inicializador de clase base y hacer que la subclase proporcione (o anule) el comportamiento.
Tim Delaney
@TimDelaney: Ah, gracias por aclarar.
Sebastian Mach
4
@TimDelaney. Creo que su comentario debería reemplazar la respuesta aceptada.
flamenco

Respuestas:

114

No hay sobrecarga de funciones en Python, lo que significa que no puede tener varias funciones con el mismo nombre pero con diferentes argumentos.

En su ejemplo de código, no está sobrecargando __init__() . Lo que sucede es que la segunda definición vuelve a vincular el nombre __init__al nuevo método, lo que hace que el primer método sea inaccesible.

En cuanto a su pregunta general sobre constructores, Wikipedia es un buen punto de partida. Para cosas específicas de Python, recomiendo ampliamente los documentos de Python .

NPE
fuente
¿También significa que el archivo fuente se analiza (¿interpreta?) Secuencialmente? ¿Puedo estar seguro de que cualquier función que haya definido más adelante sobrescribe la definida con el mismo nombre antes? :( mi Q suena tonto ... debería haberlo sabido
0xc0de
4
@ 0xc0de: En Python, las definiciones de funciones son en realidad declaraciones ejecutables y se ejecutan de arriba a abajo, así que sí.
NPE
1
@ 0xc0de Lo que en realidad sucede es que el cuerpo de la clase se ejecuta en su propio espacio de nombres, ese espacio de nombres luego se pasa a la metaclase (entre con el nombre y las bases). Las definiciones de funciones simplemente están creando una función con el cuerpo especificado y asignándola a su nombre. La última tarea __init__será la que termine en la clase.
skyking
64

¿Por qué a los constructores se les llama "Constructores"?

El constructor (con nombre __new__) crea y devuelve una nueva instancia de la clase. Entonces, el C.__new__método de clase es el constructor de la clase C.

El C.__init__método de instancia se llama en una instancia específica, después de que se crea, para inicializarlo antes de pasarlo de nuevo al llamador. Entonces ese método es el inicializador para nuevas instancias de C.

¿En qué se diferencian de los métodos de una clase?

Como se indica en la documentación oficial, __init__ se llama después de que se crea la instancia . Otros métodos no reciben este tratamiento.

Cual es su proposito?

El propósito del constructor C.__new__es definir un comportamiento personalizado durante la construcción de una nueva Cinstancia.

El propósito del inicializador C.__init__es definir la inicialización personalizada de cada instancia de Cdespués de su creación.

Por ejemplo, Python te permite hacer:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

Pero si desea que cada instancia de Testtenga un atributo xigual a 10, puede poner ese código dentro __init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

Cada método de instancia (un método llamado en una instancia específica de una clase) recibe la instancia como su primer argumento. Ese argumento se denomina convencionalmente self.

Los métodos de clase, como el constructor __new__, reciben la clase como primer argumento.

Ahora, si desea valores personalizados para el xatributo, todo lo que tiene que hacer es pasar ese valor como argumento a __init__:

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

Espero que esto te ayude a despejar algunas dudas, y como ya has recibido buenas respuestas a las otras preguntas, me detendré aquí :)

Rik Poggi
fuente
9

Las clases son simplemente planos para crear objetos. El constructor es un código que se ejecuta cada vez que crea un objeto. Por lo tanto, no tiene sentido tener dos constructores. Lo que pasa es que el segundo sobrescribe al primero.

Para lo que normalmente los usa es para crear variables para ese objeto como este:

>>> class testing:
...     def __init__(self, init_value):
...         self.some_value = init_value

Entonces, lo que podría hacer es crear un objeto de esta clase como este:

>>> testobject = testing(5)

El testobject tendrá entonces un objeto llamado some_valueque en esta muestra será 5.

>>> testobject.some_value
5

Pero no es necesario establecer un valor para cada objeto como lo hice en mi muestra. También puedes hacer esto:

>>> class testing:
...     def __init__(self):
...         self.some_value = 5

entonces el valor de some_value será 5 y no es necesario que lo establezca cuando cree el objeto.

>>> testobject = testing()
>>> testobject.some_value
5

el >>> y ... en mi muestra no es lo que escribes. Así se vería en pyshell ...

Niclas Nilsson
fuente
No hay problema, me alegro de que te haya ayudado :)
Niclas Nilsson
1

Los constructores se llaman automáticamente cuando crea un nuevo objeto, "construyendo" así el objeto. La razón por la que puede tener más de un inicio es porque los nombres son solo referencias en Python, y se le permite cambiar lo que cada variable hace referencia cuando lo desee (por lo tanto, escritura dinámica)

def func(): #now func refers to an empty funcion
    pass
...
func=5      #now func refers to the number 5
def func():
    print "something"    #now func refers to a different function

en la definición de tu clase, solo mantiene la última

Ryan Haining
fuente
0

No existe la noción de sobrecarga de métodos en Python. Pero puede lograr un efecto similar especificando argumentos opcionales y de palabras clave

NLPer
fuente