def - super class self__ init__ python
Diferencia entre super() y llamando a superclase directamente (1)
Para herencia simple, super()
es solo una forma más elegante de referirse al tipo base. De esa manera, hace que el código sea más fácil de mantener, por ejemplo, en caso de que quiera cambiar el nombre del tipo base. Cuando está utilizando super
todas partes, solo necesita cambiarlo en la línea de class
.
Sin embargo, el beneficio real viene con herencia múltiple. Cuando se usa super
, una sola llamada no solo llamará automáticamente al método de todos los tipos básicos (en el orden de herencia correcto), sino que también se asegurará de que cada método solo se llame una vez.
Básicamente, esto permite que los tipos tengan una propiedad de diamond , por ejemplo, usted tiene una base única tipo A
y dos tipos B
y C
que ambos derivan de A
Y luego tienes un tipo D
que hereda tanto de B
como de C
(haciéndolo heredar implícitamente de A
también, dos veces). Si llama ahora explícitamente a los métodos de los tipos básicos, terminará llamando dos veces al método de A. Pero usando super
, solo lo llamará una vez:
class A (object):
def __init__ (self):
super().__init__()
print(''A'')
class B (A):
def __init__ (self):
super().__init__()
print(''B'')
class C (A):
def __init__ (self):
super().__init__()
print(''C'')
class D (C, B):
def __init__ (self):
super().__init__()
print(''D'')
Cuando ahora creamos una instancia de D
, obtenemos el siguiente resultado:
>>> D()
A
B
C
D
<__main__.D object at 0x000000000371DD30>
Ahora, hagamos todo eso nuevamente llamando manualmente al método del tipo base:
class A2 (object):
def __init__ (self):
print(''A2'')
class B2 (A2):
def __init__ (self):
A2.__init__(self)
print(''B2'')
class C2 (A2):
def __init__ (self):
A2.__init__(self)
print(''C2'')
class D2 (C2, B2):
def __init__ (self):
B2.__init__(self)
C2.__init__(self)
print(''D2'')
Y esta es la salida:
>>> D2()
A2
B2
A2
C2
D2
<__main__.D2 object at 0x0000000003734E48>
Como puedes ver, A2
ocurre dos veces. Esto no suele ser lo que quieres. Se vuelve aún más complicado cuando se llama manualmente el método de uno de sus tipos básicos que usa super
. Así que, en lugar de eso, deberías usar super()
para asegurarte de que todo funcione, y también para no tener que preocuparte demasiado.
En Python 2.7 y 3, uso el siguiente método para llamar a la función de una super-clase:
class C(B):
def __init__(self):
B.__init__(self)
Veo que también es posible reemplazar B.__init__(self)
con super(B, self).__init__()
y en python3 super().__init__()
.
¿Hay alguna ventaja o desventaja en hacer esto de cualquier manera? Tiene más sentido llamarlo desde B
directamente para mí, al menos, pero tal vez haya una buena razón por la que super()
solo se puede usar cuando se usan metaclases (que generalmente evito).