2010-11-29 11 views
17

Durante todo el tiempo que he estado usando:Python: ¿cuál es la mejor manera de llamar al método de superclase?

SuperClass.__init__(self, *args, **kwargs) 

Mi razón es que esto demuestra explícitamente qué superclase se utiliza, sobre todo en el caso de la herencia múltiple.

Sin embargo, otros códigos me encontré con el uso

super(MyClass, self).__init__(*args, **kwargs) 

lugar.

Esto podría llegar a ser ambiguo cuando se utiliza en:

class MyClass(SuperClass1, SuperClass2): 
    def __init__(self, *args, **kwargs): 
     super(MyClass, self).__init__(*args, **kwargs) #which SuperClass is being used? 

me gustaría saber por qué esta forma de llama está ampliamente adoptado? ¿Alguna ventaja en absoluto?

Respuesta

6

Para las nuevas clases de estilo que heredan de object, se utiliza super.

El (resolución orden método) __mro__ atributo de los tipo listas el orden de búsqueda de resolución método utilizado por super.

>>> class X(object): 
    pass 

>>> class Y(object): 
    pass 

>>> class Z(X, Y): 
    pass 

>>> Z.__mro__ 
(<class '__main__.Z'>, <class '__main__.X'>, <class '__main__.Y'>, <type 'object'>) 

Esto especifica el orden de Z. Puesto que es Z(X, Y), X es primero en la jerarquía. Si hubiera sido Z(Y, X), Y hubiera precedido a más de X.

Para las clases de estilo anterior, se usa SuperClass.__init__(self, *args, **kwargs).

ACTUALIZACIÓN:

Para su pregunta de qué se está utilizando SuperClass.

>>> class First(object): 
    pass 

>>> class Second(object): 
    def __init__(self, *args, **kwargs): 
     print 'Second __init__ called' 

>>> class MInherit(First, Second): 
    def __init__(self): 
     super(MInherit, self).__init__() 

>>> i = MInherit() 
Second __init__ called 

En primer lugar, First se comprobará para ver si hay alguna toma __init__, ya First es lo primero en el MRO. Como en este caso 'First' no tiene un __init__, se llama a Second. Si hubiera habido __init__ en First, solo se habría llamado.

21

La razón de que es super prefereable para los modernos (nuevo estilo) clases es que permite cooperativa herencia múltiple. Aquí hay un ejemplo.

>>> class Foo(object): 
...  def display(self): 
...   print "In Foo" 
... 
>>> class Foo2(Foo): 
...  def display(self): 
...   print "In Foo2" 
...   super(Foo2, self).display() 
...   print "Back in Foo2" 
... 
>>> class Bar(Foo): 
...  def display(self): 
...   print "In Bar" 
...   super(Bar, self).display() 
...   print "Back in Bar" 
... 
>>> class FooBar(Foo2, Bar): 
...  pass 
... 
>>> FooBar().display() 
In Foo2 
In Bar 
In Foo 
Back in Bar 
Back in Foo2 
>>> class BarFoo(Bar, Foo2): 
...  pass 
... 
>>> BarFoo().display() 
In Bar 
In Foo2 
In Foo 
Back in Foo2 
Back in Bar 

Tenga en cuenta que yo no hice nada para cambiar el método display en las superclases pero tengo diferentes métodos display en las subclases cambiando el orden en el que me organizó las superclases. BarFoo y FooBar tienen diferentes métodos. Esto es porque tienen diferentes órdenes Resolución Método

>>> BarFoo.__mro__ 
(<class '__main__.BarFoo'>, <class '__main__.Bar'>, <class '__main__.Foo2'>, <class '__main__.Foo'>, <type 'object'>) 
>>> FooBar.__mro__ 
(<class '__main__.FooBar'>, <class '__main__.Foo2'>, <class '__main__.Bar'>, <class '__main__.Foo'>, <type 'object'>) 

Esto significa que super remite a una clase diferente para cada subclase que se llama en.Esto permite que cada método principal cambie una pequeña parte de lo que está sucediendo y aún así permita que cada una de las otras superclases contribuya a la llamada al método, siempre que estén dispuestas a jugar bien.

3

Además de las buenas respuestas ya publicadas, he aquí algo de información adicional:

  • clases de estilo antiguo (aquellos que no se derivan de objeto) tiene una orden de resolución de métodos primero en profundidad. Las clases antiguas llaman a sus superclases de la forma en que estás acostumbrado.

  • Las clases de nuevo estilo (aquellas que derivan del objeto) tienen un orden de resolución de método más complicado. En el nivel más alto, es similar a la amplitud primero, pero es más complejo que eso. Vea esto page para una excelente explicación. El uso de "super()" permite que las nuevas clases de estilo sigan este orden de resolución de métodos.

  • Si está utilizando clases de estilo nuevo, puede seguir utilizando el estilo antiguo de las llamadas super clases y su código seguirá funcionando. Las diferencias solo se hacen evidentes para patrones de herencia múltiple más complicados.

Cuestiones relacionadas