Ik heb drie klassen: A
, B
en C
.
C
erft van A
en B
(in deze volgorde). De constructorhandtekeningen van A
en B
zijn verschillend. Hoe kan ik de __init__
methoden van beide bovenliggende klassen aanroepen?
Mijn poging in 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()
geeft de fout:
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
Ik heb deze brongevonden die meervoudige overerving uitlegt met verschillende reeksen argumenten, maar ze stellen voor om *args
en **kwargs
om voor alle argumenten te gebruiken. Ik vind dit erg lelijk, omdat ik aan de aanroep van de constructor in de child-klasse niet kan zien wat voor soort parameters ik doorgeef aan de parent-klassen.
Antwoord 1, autoriteit 100%
Gebruik geensuper(baseclass, ...)
tenzij u weet wat u doet. Het eerste argument voor super()
vertelt het welke klasse het moet overslaanbij het zoeken naar de volgende methode om te gebruiken. bijv. super(A, ...)
zal naar de MRO kijken, A
vinden en vervolgens __init__
zoeken op de volgendebasisklasse, nietA
zelf. Voor C
is de MRO (C, A, B, object)
, dus super(A, self).__init__
vindt B.__init__
.
In deze gevallen wilt u geen coöperatieve overerving gebruiken, maar in plaats daarvan rechtstreeks verwijzen naar A.__init__
en B.__init__
. super()
mag alleen worden gebruikt als de methoden die u aanroept de dezelfde handtekeninghebben of niet-ondersteunde argumenten inslikken met *args
en **vargs
. In dat geval zou slechts die ene super(C, self).__init__()
-aanroep nodig zijn en zou de volgende klasse in de MRO-volgorde zorgen voor het koppelen van de aanroep.
Anders gezegd: als je super()
gebruikt, kun je niet weten welke klasse de volgende is in de MRO, zodat die klasse de argumenten die je eraan doorgeeft beter ondersteunt. Als dat niet het geval is, nietgebruik super()
.
De basis __init__
methoden rechtstreeks aanroepen:
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)
Coöperatieve super()
gebruiken:
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)