Así que seguí Super Considered Dañino de Python y fui a probar sus ejemplos.
Sin embargo, el Ejemplo 1-3 , que se supone que muestra la forma correcta de llamar super
cuando se manejan __init__
métodos que esperan diferentes argumentos, no funciona.
Esto es lo que obtengo:
~ $ python example1-3.py
MRO: ['E', 'C', 'A', 'D', 'B', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B
Traceback (most recent call last):
File "Download/example1-3.py", line 27, in <module>
E(arg=10)
File "Download/example1-3.py", line 24, in __init__
super(E, self).__init__(arg, *args, **kwargs)
File "Download/example1-3.py", line 14, in __init__
super(C, self).__init__(arg, *args, **kwargs)
File "Download/example1-3.py", line 4, in __init__
super(A, self).__init__(*args, **kwargs)
File "Download/example1-3.py", line 19, in __init__
super(D, self).__init__(arg, *args, **kwargs)
File "Download/example1-3.py", line 9, in __init__
super(B, self).__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters
Parece que en object
sí mismo viola una de las mejores prácticas mencionadas en el documento, que es que los métodos que utilicen super
deben aceptar *args
y **kwargs
.
Ahora, obviamente, el Sr. Knight esperaba que sus ejemplos funcionaran, entonces, ¿es esto algo que se cambió en las versiones recientes de Python? Revisé 2.6 y 2.7, y falla en ambos.
Entonces, ¿cuál es la forma correcta de abordar este problema?
object
, y se asegura a la llamadaobject
'S__init__
correctamente.__init__
en cuenta que onobject
ignora silenciosamente cualquier parámetro en Python 2.5. Esto cambió en Python 2.6.Respuestas:
A veces, dos clases pueden tener algunos nombres de parámetros en común. En ese caso, no puede
**kwargs
quitar los pares clave-valor o eliminarlos*args
. En su lugar, puede definir unaBase
clase queobject
, a diferencia de , absorbe / ignora argumentos:rendimientos
Tenga en cuenta que para que esto funcione,
Base
debe ser la penúltima clase en el MRO.fuente
Base
llamarsuper(Base, self).__init__()
?Base
debe llegar al final del MRO (exceptoobject
). Llamarobject.__init__
no hace nada, por lo que está bien no llamarsuper(Base, self).__init__()
. De hecho, creo que puede ser más claro no incluirsuper(Base, self).__init__()
para llevar a casa el punto queBase
es el final de la línea.Si va a tener mucha herencia (ese es el caso aquí), le sugiero que pase todos los parámetros usando
**kwargs
, y luegopop
inmediatamente después de usarlos (a menos que los necesite en las clases superiores).Esta es la forma más sencilla de resolver ese tipo de problemas.
fuente
Como se explica en super () de Python considerado super , una forma es hacer que la clase se coma los argumentos que requiere y pase el resto. Por lo tanto, cuando la cadena de llamadas llega
object
, todos los argumentos se han comido yobject.__init__
se llamarán sin argumentos (como se espera). Entonces su código debería verse así:fuente
E(arg = 10)
? No me gusta este método, necesito conocer el MRO de antemano para poder usarlo. El otro método en el que escribo una "clase raíz" que heredaobject
parece mucho más limpio.super
, por lo que este enfoque podría ser bastante teórico.