Super método de Python y alternativas de llamada.

Veo en todas partes ejemplos que los métodos de súper clase deberían ser llamados por:

super(SuperClass, instance).method(args) 

¿Hay alguna desventaja de hacer?

 SuperClass.method(instance, args) 

Considere la siguiente situación:

 class A(object): def __init__(self): print('Running A.__init__') super(A,self).__init__() class B(A): def __init__(self): print('Running B.__init__') # super(B,self).__init__() A.__init__(self) class C(A): def __init__(self): print('Running C.__init__') super(C,self).__init__() class D(B,C): def __init__(self): print('Running D.__init__') super(D,self).__init__() foo=D() 

Así que las clases forman un llamado diamante de herencia:

  A / \ BC \ / D 

Ejecutando los rendimientos del código

 Running D.__init__ Running B.__init__ Running A.__init__ 

Eso es malo porque el __init__ C se omite. La razón de esto es porque el __init__ B llama a __init__ A directamente.

El propósito de super es resolver diamantes de herencia . Si no quieres comentar

 # super(B,self).__init__() 

y comentar

 A.__init__(self) 

El código produce el resultado más deseable:

 Running D.__init__ Running B.__init__ Running C.__init__ Running A.__init__ 

Ahora todos los métodos __init__ son llamados. Observe que en el momento en que define B.__init__ podría pensar que super(B,self).__init__() es lo mismo que llamar a A.__init__(self) , pero estaría equivocado. En la situación anterior, super(B,self).__init__() realidad llama a C.__init__(self) .

Holy smokes, B no sabe nada acerca de C , y sin embargo, super(B,self) sabe __init__ llamar a C__init__ ? La razón es porque self.__class__.mro() contiene C En otras palabras, el self (o en lo anterior, foo ) sabe acerca de C

Así que ten cuidado, los dos no son fungibles. Pueden dar resultados muy diferentes.

El uso de super tiene trampas. Se necesita un nivel considerable de coordinación entre todas las clases en el diagtwig de herencia. (Deben, por ejemplo, tener la misma firma de llamada para __init__ , ya que cualquier __init__ particular no sabría qué otro __init__ super podría llamar a continuación, o bien usar **kwargs .) Además, debe ser coherente con el uso de super todas partes. Salta una vez (como en el ejemplo anterior) y derrotas todo el propósito de super . Vea el enlace para más trampas.

Si tiene control total sobre la jerarquía de su clase, o si evita los diamantes de herencia, entonces no hay necesidad de super .

No hay penalización tal como está, aunque tu ejemplo es un tanto erróneo. En el primer ejemplo, debería ser

 super(SubClass, instance).method(args) # Sub, not SuperClass 

y eso me lleva a citar los documentos de Python :

Hay dos casos de uso típicos para super . En una jerarquía de clases con herencia única, super se puede usar para referirse a clases primarias sin nombrarlas explícitamente, lo que hace que el código sea más fácil de mantener. Este uso es muy similar al uso de super en otros lenguajes de progtwigción.

El segundo caso de uso es admitir la herencia múltiple cooperativa en un entorno de ejecución dynamic. Este caso de uso es exclusivo de Python y no se encuentra en idiomas comstackdos de forma estática o en idiomas que solo admiten herencia simple. Esto hace posible implementar “diagtwigs de diamante” donde varias clases base implementan el mismo método. El buen diseño dicta que este método tenga la misma firma de llamada en todos los casos (porque el orden de las llamadas se determina en el tiempo de ejecución, porque ese orden se adapta a los cambios en la jerarquía de clases y porque ese orden puede incluir clases de hermanos que son desconocidas antes del tiempo de ejecución ).

Básicamente, al usar el primer método, no tiene que codificar su clase principal para jerarquías de una sola clase, y simplemente no puede hacer lo que quiere (eficiente / efectivamente) usando el segundo método cuando usa múltiples herencia.