I have the following python code :
class A():
def __init__(self) -> None:
print("init A")
self.N = 0
class B1(A):
def __init__(self) -> None:
print("init B1")
super().__init__()
self.N = 1
class B2(A):
def __init__(self, Q) -> None:
print("init B2")
super().__init__()
self.Q = Q
class C(B1, B2):
def __init__(self) -> None:
print("init C")
super().__init__()
There is a main class A
, then two classes B1
and B2
both inheriting A
, and then a class C
inheriting B1
and B2
:
-----
| A |
-----
/ \
/ \
------ ------
| B1 | | B2 |
------ ------
\ /
\ /
-----
| C |
-----
As you can see, the number of arguments for the initialization of B1
and B2
is not the same : B2
need a value of Q
while B1
doesn't.
As it is, when I try to create an instance of C
with the code c = C()
I get the following error :
init C
init B1
Traceback (most recent call last):
File "AA.py", line 26, in <module>
c = C()
File "AA.py", line 24, in __init__
super().__init__()
File "AA.py", line 12, in __init__
super().__init__()
TypeError: __init__() missing 1 required positional argument: 'Q'
I did not manage to find a way to fix this : in the initialization of C
, initialize the two parent classes separately. I tried super(B1).__init__(...)
or B1.__init__(...)
, unsuccessfully...
CodePudding user response:
Rewrite the classes to make cooperative inheritance work properly.
class A:
def __init__(self, **kwargs) -> None:
super().__init_(**kwargs)
print("init A")
self.N = 0
class B1(A):
def __init__(self, **kwargs) -> None:
print("init B1")
super().__init_(**kwargs)
self.N = 1
class B2(A):
def __init__(self, *, Q, **kwargs) -> None:
print("init B2")
super().__init_(**kwargs)
self.Q = Q
class C(B1, B2):
def __init__(self) -> None:
print("init C")
super().__init_(**kwargs)
c = C(Q=3)
All __init__
(even A
, to allow it to work with other base classes) functions accept arbitrary keyword arguments. Any keyword argument that isn't used to set an explicitly declared parameter will be passed up the chain. Eventually, all keyword arguments should be accounted for in this fashion before super().__init__
invokes object.__init__
.
When you call C.__init__
, the Q
argument will be passed first to B2.__init__
, which will pass it to B1.__init__
, which uses it and passes the now-empty kwargs
on to A.__init__
, and ultimately to object.__init__
.