Então eu estava seguindo Super Considered Harmful do Python e fui testar seus exemplos.
No entanto, o Exemplo 1-3 , que deveria mostrar a maneira correta de chamar super
ao lidar com __init__
métodos que esperam argumentos diferentes, não funciona.
Isso é o que eu recebo:
~ $ 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 por object
si só viola uma das melhores práticas mencionadas no documento, que é os métodos que o uso super
deve aceitar *args
e **kwargs
.
Obviamente, o Sr. Knight esperava que seus exemplos funcionassem, então isso é algo que foi alterado nas versões recentes do Python? Verifiquei 2.6 e 2.7 e falha em ambos.
Então, qual é a maneira correta de lidar com esse problema?
object
, e torna-se a chamadaobject
é__init__
corretamente.__init__
onobject
ignora silenciosamente todos os parâmetros do Python 2.5. Isso mudou no Python 2.6.Respostas:
Às vezes, duas classes podem ter alguns nomes de parâmetros em comum. Nesse caso, você não pode
**kwargs
retirar os pares de valores-chave ou removê-los*args
. Em vez disso, você pode definir umaBase
classe queobject
, ao contrário , absorve / ignora argumentos:rendimentos
Observe que, para que isso funcione,
Base
deve ser a penúltima turma do MRO.fonte
Base
ligarsuper(Base, self).__init__()
?Base
deve vir no final do MRO (exceto paraobject
). Ligarobject.__init__
não faz nada, então não há problema em não ligarsuper(Base, self).__init__()
. Na verdade, acho que pode ser mais claro não incluir,super(Base, self).__init__()
para esclarecer, o ponto queBase
é o fim da linha.Se você vai ter muita herança (esse é o caso aqui), sugiro que você passe todos os parâmetros usando
**kwargs
, e entãopop
eles logo após usá-los (a menos que você precise deles nas classes superiores).Essa é a maneira mais simples de resolver esse tipo de problema.
fonte
Conforme explicado no super () do Python, considerado super , uma maneira é fazer com que a classe coma os argumentos de que necessita e passe o resto adiante. Assim, quando a cadeia de chamada chega
object
, todos os argumentos foram comidos eobject.__init__
serão chamados sem argumentos (como esperado). Portanto, seu código deve ser assim:fonte
E(arg = 10)
? Não gosto desse método, preciso conhecer o MRO com antecedência para poder usá-lo. O outro método em que escrevo uma "classe raiz" que herdaobject
parece muito mais limpo.super
, então esta abordagem pode ser bastante teórica.