method - Python se extiende con-usando super() Python 3 vs Python 2
python super constructor (4)
Originalmente quería hacer esta pregunta , pero luego descubrí que ya se había pensado antes ...
Buscando en Google Encontré este ejemplo de extender configparser . Lo siguiente funciona 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 sobre los estilos Python New Class vs. Old Class (por ejemplo, here . Y ahora me pregunto, puedo hacerlo:
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"""
Pero, ¿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)
En resumen, son equivalentes. Tengamos una vista de historial:
(1) al principio, la función se ve así.
class MySubClass(MySuperClass):
def __init__(self):
MySuperClass.__init__(self)
(2) para hacer que el código sea más abstracto (y más portátil). Un método común para obtener Super-Class se inventa como:
super(<class>, <instance>)
Y la función init puede ser:
class MySubClassBetter(MySuperClass):
def __init__(self):
super(MySubClassBetter, self).__init__()
Sin embargo, requerir un pase explícito tanto de la clase como de la instancia rompe la regla DRY (Do not Repeat Yourself).
(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/
En un único caso de herencia (cuando subclasifica una sola clase), su 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 complicadas si introduce herencia múltiple (subclases 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á solo la primera.
En tales casos, realmente deberías usar super
si puedes, 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 funcionará correctamente (en Python 3 pero podrías volver a trabajarlo 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 usan super
aunque no tengan sus propias clases base.
Lo que hace super
es: llama al método de la clase siguiente en MRO (orden de resolución de método). El MRO para C
es: (C, A, B, object)
. Puede imprimir C.__mro__
para verlo.
Entonces, C
hereda __init__
de A
y super
en A.__init__
llama B.__init__
( B
sigue a A
en MRO).
Entonces al no hacer nada en C
, terminas llamando a ambos, que es lo que quieres.
Ahora, si no estuvieras usando super
, terminarías heredando A.__init__
(como antes) pero esta vez no hay nada que pueda llamar B.__init__
por ti.
class A:
def __init__(self):
print(''A'')
class B:
def __init__(self):
print(''B'')
class C(A, B):
pass
C()
#prints:
#A
Para solucionarlo, debe definir C.__init__
:
class C(A, B):
def __init__(self):
A.__init__(self)
B.__init__(self)
El problema es que en los árboles MI más complicados, los métodos __init__
de algunas clases pueden ser llamados más de una vez, mientras que super / MRO garantizan que se invoquen solo una vez.
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
super()
(sin argumentos) fue introducido en Python 3 (junto con__class__
):super() -> same as super(__class__, self)
entonces ese sería el equivalente de Python 2 para las clases de nuevo estilo:
super(CurrentClass, self)
para las clases de estilo antiguo que siempre puedes usar:
class Classname(OldStyleParent): def __init__(self, *args, **kwargs): OldStyleParent.__init__(self, *args, **kwargs)