J'ai trois classes: A
, B
et C
.
C
hérite de A
et B
(dans cet ordre). Les signatures de constructeur de A
et B
sont différentes. Comment puis-je appeler le __init__
méthodes des deux classes parentes?
Mon effort dans le code:
class A(object):
def __init__(self, a, b):
super(A, self).__init__()
print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))
class B(object):
def __init__(self, q):
super(B, self).__init__()
print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))
class C(A, B):
def __init__(self):
super(A, self).__init__(1, 2)
super(B, self).__init__(3)
c = C()
renvoie l'erreur:
Traceback (most recent call last):
File "test.py", line 16, in <module>
c = C()
File "test.py", line 13, in __init__
super(A, self).__init__(1, 2)
TypeError: __init__() takes 2 positional arguments but 3 were given
J'ai trouvé cette ressource qui explique l'héritage mutiple avec différents ensembles d'arguments, mais ils suggèrent d'utiliser *args
et **kwargs
à utiliser pour tous les arguments. Je considère cela comme très laid, car je ne peux pas voir de l'appel du constructeur dans la classe enfant quel type de paramètres je passe aux classes parent.
Faites pas utilisez super(baseclass, ...)
sauf si vous savez ce que vous faites. Le premier argument de super()
lui indique quelle classe ignorer lors de la recherche de la prochaine méthode à utiliser. Par exemple. super(A, ...)
va regarder le MRO, trouver A
, puis commencer à chercher __init__
sur la classe de base suivante, pas = A
lui-même. Pour C
, le MRO est (C, A, B, object)
, Donc super(A, self).__init__
trouvera B.__init__
.
Dans ces cas, vous ne souhaitez pas utiliser l'héritage coopératif mais référencer directement A.__init__
Et B.__init__
À la place. super()
ne doit être utilisé que si les méthodes que vous appelez ont la même signature ou avalent des arguments non pris en charge avec *args
et **vargs
. Dans ce cas, un seul appel super(C, self).__init__()
serait nécessaire et la classe suivante dans l'ordre MRO se chargerait de chaîner l'appel.
Autrement dit: lorsque vous utilisez super()
, vous ne pouvez pas savoir quelle classe sera la prochaine dans le MRO, afin que cette classe prenne mieux en charge les arguments que vous lui passez. Si ce n'est pas le cas, n'utilisez pas super()
.
Appel direct des méthodes de base __init__
:
class A(object):
def __init__(self, a, b):
print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))
class B(object):
def __init__(self, q):
print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))
class C(A, B):
def __init__(self):
# Unbound functions, so pass in self explicitly
A.__init__(self, 1, 2)
B.__init__(self, 3)
Utilisation de la coopérative super()
:
class A(object):
def __init__(self, a=None, b=None, *args, **kwargs):
super().__init__(*args, **kwargs)
print('Init {} with arguments {}'.format(self.__class__.__name__, (a, b)))
class B(object):
def __init__(self, q=None, *args, **kwargs):
super().__init__(*args, **kwargs)
print('Init {} with arguments {}'.format(self.__class__.__name__, (q)))
class C(A, B):
def __init__(self):
super().__init__(a=1, b=2, q=3)