J'ai donc suivi Super Considered Harmful de Python et suis allé tester ses exemples.
Cependant, l' exemple 1-3 , qui est censé montrer la manière correcte d'appeler super
lors de la gestion de __init__
méthodes qui attendent des arguments différents, ne fonctionne pas.
Voici ce que je reçois:
~ $ 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
Il semble que object
lui - même viole l'une des meilleures pratiques mentionnées dans le document, à savoir que les méthodes qui utilisent super
doivent accepter *args
et **kwargs
.
Maintenant, évidemment, M. Knight s'attendait à ce que ses exemples fonctionnent, alors est-ce quelque chose qui a été changé dans les versions récentes de Python? J'ai vérifié 2.6 et 2.7, et cela échoue sur les deux.
Alors, quelle est la bonne façon de traiter ce problème?
object
, et il veille à l' appelobject
est__init__
correctement.__init__
surobject
ignore silencieusement tous les paramètres de Python 2.5. Cela a changé dans Python 2.6.Réponses:
Parfois, deux classes peuvent avoir des noms de paramètres en commun. Dans ce cas, vous ne pouvez pas
**kwargs
supprimer ou supprimer les paires clé-valeur*args
. Au lieu de cela, vous pouvez définir uneBase
classe qui, contrairement àobject
, absorbe / ignore les arguments:rendements
Notez que pour que cela fonctionne,
Base
doit être l'avant-dernière classe du MRO.la source
Base
appelersuper(Base, self).__init__()
?Base
faut arriver à la fin du MRO (sauf pourobject
). Appelerobject.__init__
ne fait rien, il est donc normal de ne pas appelersuper(Base, self).__init__()
. En fait, je pense qu'il serait peut-être plus clair de ne pas incluresuper(Base, self).__init__()
pour ramener à la maison le point quiBase
est la fin de la ligne.Si vous allez avoir beaucoup d'héritage (c'est le cas ici), je vous suggère de passer tous les paramètres en utilisant
**kwargs
, puispop
les juste après les avoir utilisés (sauf si vous en avez besoin dans les classes supérieures).C'est le moyen le plus simple de résoudre ce genre de problèmes.
la source
Comme expliqué dans super () de Python considéré comme super , une façon est de faire en sorte que la classe mange les arguments dont elle a besoin et transmet le reste. Ainsi, lorsque la chaîne d'appels atteint
object
, tous les arguments ont été mangés etobject.__init__
seront appelés sans arguments (comme il s'y attend). Donc, votre code devrait ressembler à ceci:la source
E(arg = 10)
? Je n'aime pas cette méthode, j'ai besoin de connaître le MRO à l'avance pour pouvoir l'utiliser. L'autre méthode où j'écris une "classe racine" qui hérite deobject
semble beaucoup plus propre.super
, donc cette approche pourrait en effet être plutôt théorique.