Multiple inheritance in python3 with different signatures
Solution 1:
Do not use super(baseclass, ...)
unless you know what you are doing. The first argument to super()
tells it what class to skip when looking for the next method to use. E.g. super(A, ...)
will look at the MRO, find A
, then start looking for __init__
on the next baseclass, not A
itself. For C
, the MRO is (C, A, B, object)
, so super(A, self).__init__
will find B.__init__
.
For these cases, you don't want to use cooperative inheritance but directly reference A.__init__
and B.__init__
instead. super()
should only be used if the methods you are calling have the same signature or will swallow unsupported arguments with *args
and **vargs
. In that case just the one super(C, self).__init__()
call would be needed and the next class in the MRO order would take care of chaining on the call.
Putting it differently: when you use super()
, you can not know what class will be next in the MRO, so that class better support the arguments you pass to it. If that isn't the case, do not use super()
.
Calling the base __init__
methods directly:
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)
Using cooperative 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)