python - sirve - ¿Debería__init__() llamar al__init__() de la clase padre?
metodo str python (6)
Estoy usando eso en Objective-C. Tengo este constructo:
- (void)init {
if (self = [super init]) {
// init class
}
return self;
}
¿Debería Python también llamar a la implementación de la clase padre para __init__
?
class NewClass(SomeOtherClass):
def __init__(self):
SomeOtherClass.__init__(self)
# init class
¿Esto también es verdadero / falso para __new__()
y __del__()
?
Editar: hay una pregunta muy similar: Herencia y Anulación __init__
en Python
En Python, llamar a la __init__
'' __init__
es opcional. Si lo llama, también es opcional usar el super
o indicar explícitamente la superclase:
object.__init__(self)
En el caso de un objeto, no es estrictamente necesario llamar al supermétodo, ya que el supermétodo está vacío. Lo mismo para __del__
.
OTOH, para __new__
, debería llamar al __new__
y usar su retorno como el objeto recién creado, a menos que explícitamente desee devolver algo diferente.
En la respuesta de Anon:
"Si necesitas algo de la __init__
de __init__
que se debe hacer además de lo que se está haciendo en __init__
la clase actual, debes llamarlo tú mismo, ya que eso no sucederá automáticamente"
Es increíble: redacta exactamente lo contrario al principio de herencia.
No es que "algo de la __init__
de super (...) no sucederá automáticamente" , es que sucedería automáticamente, pero no sucede porque la __init__
clase __init__
es __init__
por la definición de la derivada- clas __init__
Entonces, ¿POR QUÉ definir una clase_descrita '' __init__
, ya que anula lo que se pretende cuando alguien recurre a la herencia?
Es porque uno necesita definir algo que NO se hace en la clase base '' __init__
, y la única posibilidad de obtener eso es poner su ejecución en una función'' __init__
clase __init__
.
En otras palabras, uno necesita algo en la clase base '' __init__
además de lo que se haría automáticamente en el base-classe'' __init__
si este último no se anulara.
NO lo contrario.
Entonces, el problema es que las instrucciones deseadas presentes en la clase base '' __init__
no se activan más en el momento de la creación de instancias. Para compensar esta inactivación, se requiere algo especial: llamar explícitamente a la clase base '' __init__
, para MANTENER , NO AÑADIR, la inicialización realizada por la clase base'' __init__
. Eso es exactamente lo que se dice en el documento oficial:
Un método primordial en una clase derivada puede de hecho querer extender, en lugar de simplemente reemplazar, el método de clase base del mismo nombre. Hay una manera simple de llamar directamente al método de la clase base: simplemente llame a BaseClassName.methodname (self, arguments).
http://docs.python.org/tutorial/classes.html#inheritance
Esa es toda la historia:
cuando el objetivo es MANTENER la inicialización realizada por la clase base, que es herencia pura, no se necesita nada especial, se debe evitar definir una función
__init__
en la clase derivadacuando el objetivo es REEMPLAZAR la inicialización realizada por la clase base,
__init__
debe definirse en la clase derivadacuando el objetivo es ADD procesos para la inicialización realizada por la clase base, debe definirse una clase derivada ''
__init__
'', que comprende una llamada explícita a la clase base__init__
Lo que siento asombroso en el mensaje de Anon no es solo que expresa lo contrario de la teoría de la herencia, sino que han pasado cinco tipos que votaron sin volverse, y además nadie ha reaccionado en 2 años en un hilo cuyo tema interesante debe leerse con relativa frecuencia.
No hay una regla dura y rápida. La documentación de una clase debe indicar si las subclases deben llamar al método de la superclase. Algunas veces quiere reemplazar por completo el comportamiento de las superclases y, en otras ocasiones, aumentarlo, es decir, llamar a su propio código antes y / o después de una llamada a una superclase.
Actualización: la misma lógica básica se aplica a cualquier llamada de método. Los constructores a veces necesitan una consideración especial (ya que a menudo configuran el estado que determina el comportamiento) y destructores porque hacen paralelo a los constructores (por ejemplo, en la asignación de recursos, por ejemplo, conexiones de bases de datos). Pero lo mismo podría aplicarse, por ejemplo, al método render()
de un widget.
Actualización adicional: ¿Cuál es el OPP? ¿Te refieres a OOP? No, una subclase a menudo necesita saber algo sobre el diseño de la superclase. No los detalles de la implementación interna, sino el contrato básico que la superclase tiene con sus clientes (usando clases). Esto no viola los principios de OOP de ninguna manera. Es por eso que protected
es un concepto válido en OOP en general (aunque no, por supuesto, en Python).
OMI, deberías llamarlo. Si su superclase es un object
, no debería hacerlo, pero en otros casos creo que es excepcional no llamarlo. Como ya respondieron otros, es muy conveniente que su clase ni siquiera tenga que anular __init__
, por ejemplo, cuando no tiene un estado interno (adicional) para inicializar.
Si necesita que se haga algo de __init__
de super además de lo que se está haciendo en el __init__,
la clase actual __init__,
debe llamarlo usted mismo, ya que eso no sucederá automáticamente. Pero si no necesitas nada de __init__,
de __init__,
no es necesario que lo llames. Ejemplo:
>>> class C(object):
def __init__(self):
self.b = 1
>>> class D(C):
def __init__(self):
super().__init__() # in Python 2 use super(D, self).__init__()
self.a = 1
>>> class E(C):
def __init__(self):
self.a = 1
>>> d = D()
>>> d.a
1
>>> d.b # This works because of the call to super''s init
1
>>> e = E()
>>> e.a
1
>>> e.b # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
File "<pyshell#70>", line 1, in <module>
e.b # This is going to fail since nothing in E initializes b...
AttributeError: ''E'' object has no attribute ''b''
__del__
es de la misma manera, (pero tenga cuidado de no confiar en __del__
para la finalización, considere hacerlo a través de la declaración con).
Raramente uso __new__.
Hago toda la inicialización en __init__.
Editar : (después del cambio de código)
No hay forma de que podamos decirte si necesitas o no llamar al __init__
tus padres (o a cualquier otra función). La herencia obviamente funcionaría sin esa llamada. Todo depende de la lógica de su código: por ejemplo, si todo su __init__
se hace en la clase para padres, puede omitir por completo el __init__
clase __init__
.
considere el siguiente ejemplo:
>>> class A:
def __init__(self, val):
self.a = val
>>> class B(A):
pass
>>> class C(A):
def __init__(self, val):
A.__init__(self, val)
self.a += val
>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12