propias - pasar una lista como parametro en python
forma correcta de usar super(paso de argumento) (3)
Así que estaba siguiendo el mal considerado de Python , y fui a probar sus ejemplos.
Sin embargo, en el ejemplo 1-3 , que se supone que muestra la forma correcta de llamar a super
cuando se manejan métodos __init__
que esperan diferentes argumentos, el funcionamiento 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 el object
sí viola una de las mejores prácticas mencionadas en el documento, que es que los métodos que usan super
deben aceptar *args
y **kwargs
.
Ahora, obviamente, el Sr. Knight esperaba que sus ejemplos funcionaran, ¿es esto algo que 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 lidiar con este problema?
A veces, dos clases pueden tener algunos nombres de parámetros en común. En ese caso, no puede sacar los pares clave-valor de **kwargs
o eliminarlos de *args
. En cambio, puede definir una clase Base
que, a diferencia del object
, absorba / ignore los argumentos:
class Base(object):
def __init__(self, *args, **kwargs): pass
class A(Base):
def __init__(self, *args, **kwargs):
print "A"
super(A, self).__init__(*args, **kwargs)
class B(Base):
def __init__(self, *args, **kwargs):
print "B"
super(B, self).__init__(*args, **kwargs)
class C(A):
def __init__(self, arg, *args, **kwargs):
print "C","arg=",arg
super(C, self).__init__(arg, *args, **kwargs)
class D(B):
def __init__(self, arg, *args, **kwargs):
print "D", "arg=",arg
super(D, self).__init__(arg, *args, **kwargs)
class E(C,D):
def __init__(self, arg, *args, **kwargs):
print "E", "arg=",arg
super(E, self).__init__(arg, *args, **kwargs)
print "MRO:", [x.__name__ for x in E.__mro__]
E(10)
rendimientos
MRO: [''E'', ''C'', ''A'', ''D'', ''B'', ''Base'', ''object'']
E arg= 10
C arg= 10
A
D arg= 10
B
Tenga en cuenta que para que esto funcione, Base
debe ser la penúltima clase en el MRO.
Como se explica en super () de Python, se considera super , una forma es que la clase coma los argumentos que requiere y pase el resto. Por lo tanto, cuando la cadena de llamadas alcanza el object
, se han consumido todos los argumentos, y se object.__init__
sin argumentos (como se espera). Entonces su código debería verse así:
class A(object):
def __init__(self, *args, **kwargs):
print "A"
super(A, self).__init__(*args, **kwargs)
class B(object):
def __init__(self, *args, **kwargs):
print "B"
super(B, self).__init__(*args, **kwargs)
class C(A):
def __init__(self, arg, *args, **kwargs):
print "C","arg=",arg
super(C, self).__init__(*args, **kwargs)
class D(B):
def __init__(self, arg, *args, **kwargs):
print "D", "arg=",arg
super(D, self).__init__(*args, **kwargs)
class E(C,D):
def __init__(self, arg, *args, **kwargs):
print "E", "arg=",arg
super(E, self).__init__(*args, **kwargs)
print "MRO:", [x.__name__ for x in E.__mro__]
E(10, 20, 30)
Si vas a tener mucha herencia (este es el caso aquí) te sugiero que pases todos los parámetros usando **kwargs
, y luego los **kwargs
justo después de usarlos (a menos que los necesites en las clases altas).
class First(object):
def __init__(self, *args, **kwargs):
self.first_arg = kwargs.pop(''first_arg'')
super(First, self).__init__(*args, **kwargs)
class Second(First):
def __init__(self, *args, **kwargs):
self.second_arg = kwargs.pop(''second_arg'')
super(Second, self).__init__(*args, **kwargs)
class Third(Second):
def __init__(self, *args, **kwargs):
self.third_arg = kwargs.pop(''third_arg'')
super(Third, self).__init__(*args, **kwargs)
Esta es la forma más simple de resolver ese tipo de problemas.
third = Third(first_arg=1, second_arg=2, third_arg=3)