2011-02-17 14 views
48

que veo por todas partes ejemplos de que los métodos de la clase súper deben ser llamados por:Python súper método y piden alternativas

super(SuperClass, instance).method(args) 

¿Hay alguna desventaja a hacer:

SuperClass.method(instance, args) 

Respuesta

96

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í las clases forman un llamado diamante herencia:

A 
/\ 
    B C 
    \/
    D 

Ejecución de los rendimientos del código

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

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

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

# super(B,self).__init__() 

y comentar de salida

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__ ser llamado.Tenga en cuenta que en el momento de definir B.__init__ puede pensar que super(B,self).__init__() es lo mismo que llamar al A.__init__(self), pero estaría equivocado. En la situación anterior, super(B,self).__init__() realmente llama al C.__init__(self).

santo fuma, B sabe nada acerca de C, y sin embargo super(B,self) sabe llamar C 's __init__? La razón es porque self.__class__.mro() contiene C. En otras palabras, self (o en lo anterior, foo) conoce aproximadamente C.

Ten cuidado, los dos no son fungibles. Pueden arrojar resultados muy diferentes.

Usando superhas pitfalls. Se necesita un nivel considerable de coordinación entre todas las clases en el diagrama de herencia. (Deben, por ejemplo, o bien tienen la misma firma llamado a __init__, ya que cualquier particular, __init__ no sabría qué otra __init__super podría llamar al lado, o demás use **kwargs.) Por otra parte, debe ser coherente sobre el uso de super todas partes. Omita una vez (como en el ejemplo anterior) y vence el objetivo completo de super. Vea el enlace para ver más trampas.

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

+2

+1 para el enlace super-dañino. Estaba a punto de publicarlo yo mismo. –

+0

thnx, has aclarado mi concepto erróneo. – 0xc0de

+3

[Python's super() considerado super!] (Http://rhettinger.wordpress.com/2011/05/26/super-considered-super/) muestra por qué y cómo usar 'super()'. Por cierto, con las clases de nuevo estilo y la herencia múltiple, siempre hay un diamante de herencia debido al padre 'objeto' común. – jfs

7

No hay penalidad en que está , aunque tu ejemplo es un tanto equivocado. En el primer ejemplo, debe ser

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

y que me lleva a citar el Python docs:

Hay dos casos de uso típicos para super. En una jerarquía de clases con herencia simple, se puede usar super para referirse a las clases principales 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 programación.

El segundo caso de uso es para admitir herencia múltiple cooperativa en un entorno de ejecución dinámica. Este caso de uso es exclusivo de Python y no se encuentra en los lenguajes compilados estáticamente o en los idiomas que solo admiten herencia simple. Esto hace posible implementar "diagramas de diamantes" donde múltiples clases base implementan el mismo método. Un buen diseño exige que este método tenga la misma firma de llamada en cada caso (porque el orden de las llamadas se determina en tiempo de ejecución, porque ese orden se adapta a los cambios en la jerarquía de clases, y porque esa orden puede incluir clases hermanas desconocidas antes del tiempo de ejecución)

Básicamente, al usar el primer método, no es necesario codificar su clase primaria para las jerarquías de clase única, y simplemente no puede hacer lo que quiere (eficiente/efectivamente) utilizando el segundo método cuando se usa herencia múltiple.

+1

¿Lo entiendo bien, no hay contras de usar 'super' en situaciones de herencia única? – Wolf

Cuestiones relacionadas