2012-05-07 22 views
57

Originalmente quería preguntar this question, pero luego me pareció que ya estaba pensado antes ...Python se extiende con - el uso de super() Python 3 vs Python 2

googlear alrededor me encontré con este ejemplo de extending configparser. Los siguientes trabajos con Python 3:

$ python3 
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2 
>>> from configparser import SafeConfigParser 
>>> class AmritaConfigParser(SafeConfigParser): 
...  def __init_(self): 
...   super().__init__() 
... 
>>> cfg = AmritaConfigParser() 

Pero no con Python 2:

>>> class AmritaConfigParser(SafeConfigParser): 
...  def __init__(self): 
...   super(SafeConfigParser).init() 
... 
>>> cfg = AmritaConfigParser() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in __init__ 
TypeError: must be type, not classob 

luego leí un poco en Python Nueva Clase contra Clase estilos Viejo (por ejemplo here y ahora. pregunto, no puedo hacer:

class MyConfigParser(ConfigParser.ConfigParser): 
     def Write(self, fp): 
      """override the module's original write funcition""" 
      .... 
     def MyWrite(self, fp): 
      """Define new function and inherit all others""" 

embargo, no debería llamar a init Es esto en Python 2 el equivalente:?

class AmritaConfigParser(ConfigParser.SafeConfigParser): 
    #def __init__(self): 
    # super().__init__() # Python3 syntax, or rather, new style class syntax ... 
    # 
    # is this the equivalent of the above ? 
    def __init__(self): 
     ConfigParser.SafeConfigParser.__init__(self) 
+1

En su ejemplo que no es necesario definir un '__init __()' en la subclase si lo único que hace es llamar a la superclase '__init __()' (en Python 2 o 3) - en lugar de dejar que los súper se hereden. – martineau

+0

Referencia útil: http://amyboyle.ninja/Python-Inheritance/ –

Respuesta

99
  • super() (sin argumentos) se introdujo en Python 3 (junto con __class__):

    super() -> same as super(__class__, self) 
    

    por lo que sería el Python 2 equivalente para las clases de nuevo estilo:

    super(CurrentClass, self) 
    
  • para las clases antiguas siempre se puede usar:

    class Classname(OldStyleParent): 
        def __init__(self, *args, **kwargs): 
         OldStyleParent.__init__(self, *args, **kwargs) 
    
+1

-1. Esta respuesta no me aclaro nada. En Python 2, 'super (__ clase __)' da 'NameError: nombre global '__class__' no está definido', y' super (self .__ class __) 'es erróneo también. Usted * debe * proporcionar una instancia como segundo argumento, lo que sugeriría que necesita hacer 'super (self .__ class__, self)', pero eso es ** wrong **. Si 'Class2' hereda de' Class1' y 'Class1' calls' super (self.__class__, self) .__ init __() ',' __init__' de 'Class1' se * llamará a sí mismo * al instanciar una instancia de' Class2'. – jpmc26

+0

Para aclarar un punto, obtengo 'TypeError: super() toma al menos 1 argumento (0 dado)' al tratar de llamar 'super (self .__ class __)' en Python 2. (Lo cual no tiene mucho sentido , pero demuestra la cantidad de información que falta en esta respuesta.) – jpmc26

+2

@ jpmc26: en python2 obtienes este error porque tratas de llamar '__init__()' sin argumento en el superobjeto libre (que obtienes al llamar 'super (self .__ class __) 'con un solo argumento), necesitas un súper objeto encuadernado, entonces debería funcionar:' super (CurrentClass, self) .__ init __() '. No use 'self .__ class__' porque eso siempre se referirá a la _same_ clase cuando se llama a un padre y, por lo tanto, crea un bucle infinito si ese padre también hace lo mismo. – mata

28

En un solo caso de herencia (cuando subclase sólo una clase), la nueva clase hereda los métodos de la clase base. Esto incluye __init__. Entonces, si no lo defines en tu clase, obtendrás el de la base.

Las cosas comienzan a ser complicado si se introduce la herencia múltiple (subclasificación de más de una clase a la vez). Esto se debe a que si más de una clase base tiene __init__, su clase heredará la primera.

En tales casos, realmente debería usar super si se puede, voy a explicar por qué. Pero no siempre puedes. El problema es que todas tus clases base también deben usarlo (y sus clases base también, todo el árbol).

Si ese es el caso, entonces esto también funciona correctamente (en Python 3, pero que podría volver a trabajar en Python 2 - también tiene super):

class A: 
    def __init__(self): 
     print('A') 
     super().__init__() 

class B: 
    def __init__(self): 
     print('B') 
     super().__init__() 

class C(A, B): 
    pass 

C() 
#prints: 
#A 
#B 

Observe cómo ambas clases base utilizan super a pesar de que no tienen sus propias clases base.

Lo que hace es super: se llama al método de la clase siguiente en MRO (método de resolución de orden). El MRO para C es: (C, A, B, object). Puede imprimir C.__mro__ para verlo.

Así, C__init__ hereda de A y super en A.__init__ llamadas B.__init__ (B sigue A en MRO).

Así que haciendo nada en C, se termina llamando tanto, que es lo que desea.

Ahora, si no estuviera usando super, terminaría heredando A.__init__ (como antes) pero esta vez no hay nada que llame al B.__init__ para usted.

class A: 
    def __init__(self): 
     print('A') 

class B: 
    def __init__(self): 
     print('B') 

class C(A, B): 
    pass 

C() 
#prints: 
#A 

Para solucionar esto tiene que definir C.__init__:

class C(A, B): 
    def __init__(self): 
     A.__init__(self) 
     B.__init__(self) 

El problema con esto es que en más complicados árboles MI, __init__ métodos de algunas clases pueden acabar siendo llamados más de una vez mientras súper/MRO garantiza que son llamados solo una vez.

+7

'Observe cómo ambas clases base usan super aunque no tengan sus propias clases base. Tienen. En py3k cada clase subclases objeto. – akaRem

15

En resumen, son equivalentes. Tengamos una vista de historial:

(1) al principio, la función tiene este aspecto.

class MySubClass(MySuperClass): 
     def __init__(self): 
      MySuperClass.__init__(self) 

(2) para hacer el código más abstracto (y más portátil). Un método común para obtener super-clase se inventó como:

super(<class>, <instance>) 

y la función de inicio pueden ser:

class MySubClassBetter(MySuperClass): 
     def __init__(self): 
      super(MySubClassBetter, self).__init__() 

que requiere una aprobación explícita Sin embargo, tanto de la clase y la instancia romper el DRY (Do not Repetir) gobierna un poco.

(3) en V3. Es más inteligente,

super() 

es suficiente en la mayoría de los casos. Puede consultar http://www.python.org/dev/peps/pep-3135/

0

Solo para tener un ejemplo simple y completo para Python 3, que la mayoría de la gente parece estar usando ahora.

class MySuper(object): 
    def __init__(self,a): 
     self.a = a 

class MySub(MySuper): 
    def __init__(self,a,b): 
     self.b = b 
     super().__init__(a) 

my_sub = MySub(42,'chickenman') 
print(my_sub.a) 
print(my_sub.b) 

da

42 
chickenman