I'm trying to use multiple inheritance to add some functionality to one of the existing classes that I have. The problem is that this new class and my current base class have different arguments in their constructors. Namely the new class has 1 extra argument. After some googling I understood that I can add **kwargs to the current base class(the one with one argument less). Example:
class A(object):
def __init__(self, a):
print('__init__', locals())
class B(A):
def __init__(self, a, b):
super(B, self).__init__(a)
print('__init__', locals())
class C(B):
def __init__(self, a, b):
super(C, self).__init__(a, b)
print('__init__', locals())
class D(C):
def __init__(self, a, b):
super(D, self).__init__(a, b)
print('__init__', locals())
class E(D):
def __init__(self, a, b, *args, **kwargs):
super(E, self).__init__(a, b)
print('__init__', locals())
class F(C):
def __init__(self, a, b):
super(F, self).__init__(a, b)
print('__init__', locals())
class G(F):
def __init__(self, a, b, c):
super(G, self).__init__(a, b)
print('__init__', locals())
class H(G):
def __init__(self, a, b, c):
super(H, self).__init__(a, b, c)
print('__init__', locals())
class I(E, H):
def __init__(self, a, b, c):
super(I, self).__init__(a, b, c=c)
print('__init__', locals())
for c in I.__mro__:
print(c)
I(0, 1, 2)
But I get this error:
<class '__main__.I'>
<class '__main__.E'>
<class '__main__.D'>
<class '__main__.H'>
<class '__main__.G'>
<class '__main__.F'>
<class '__main__.C'>
<class '__main__.B'>
<class '__main__.A'>
<class 'object'>
Traceback (most recent call last):
File "/tmp/c.py", line 58, in <module>
I(0,1,2)
File "/tmp/c.py", line 50, in __init__
super(I, self).__init__(a, b, c=c)
File "/tmp/c.py", line 26, in __init__
super(E, self).__init__(a, b)
File "/tmp/c.py", line 20, in __init__
super(D, self).__init__(a, b)
TypeError: __init__() missing 1 required positional argument: 'c'
This code work for me!!!
class A(object):
def __init__(self, a):
print("A class")
class B(A):
def __init__(self, a, b):
A.__init__(self,a)
print("B class")
class C(B):
def __init__(self, a, b):
B.__init__(self,a, b)
print("C class")
class D(C):
def __init__(self, a,b):
C.__init__(self,a, b)
print("D class")
class F(C):
def __init__(self, a,b):
#C.__init__(self,a, b)
print("F class")
class G(F):
def __init__(self, a, b, c):
F.__init__(self,a, b)
print("G class")
class E(D):
def __init__(self, a, b):
D.__init__(self,a, b)
print("E class")
class H(G):
def __init__(self, a,b,c):
G.__init__(self,a, b, c)
print("H class")
class I(E,H):
def __init__(self, a, b, c):
args=(a,b,c)
E.__init__(self,a,b)
H.__init__(self,a,b,c)
print('__init__', locals())
print(I.__mro__)
I(1,2,3)
As per the MRO, the call goes to H
after D
, and so, if you need to send c
, class D
will need to accept it and send 3 parameters, ie. H
will be called by D
.
E.G.:
class A(object):
def __init__(self, a):
print('a')
print('__init__', locals())
class B(A):
def __init__(self, a, b):
print('b')
super(B, self).__init__(a)
print('__init__', locals())
class C(B):
def __init__(self, a, b):
print('c')
super(C, self).__init__(a, b)
print('__init__', locals())
class D(C):
def __init__(self, a, b, *args, **kwargs):
print('d', args, kwargs)
super(D, self).__init__(a, b, args, kwargs)
print('__init__', locals())
class E(D):
def __init__(self, a, b, *args, **kwargs):
print('e', args, kwargs)
super(E, self).__init__(a, b)
print('__init__', locals())
class F(C):
def __init__(self, a, b):
print('f')
super(F, self).__init__(a, b)
print('__init__', locals())
class G(F):
def __init__(self, a, b, c):
print('g')
super(G, self).__init__(a, b)
print('__init__', locals())
class H(G):
def __init__(self, a, b, c, *args, **kwargs):
print('h')
super(H, self).__init__(a, b, c)
print('__init__', locals())
class I(E,H):
def __init__(self, a, b, c):
print('i')
super(I,self).__init__(a, b, c)
#E.__init__(self,a, b)
#H.__init__(self,a, b, c)
print('__init__', locals())
for c in I.__mro__:
print(c)
I(0, 1, 2)
This code works,
(I have changed c
as an arg instead of **kwarg
).
Other way would be if you swap the E
, H
inheritance order, the MRO works out and you won't need to do it, or use E.__init__()
and H.__init__()
separately. In that case, MRO changes again, and common classes will be called twice if needed.
For MRO, I have found this answer and this blog post by Guido Van Rossum (also linked in the other answer) which might help you get insight on the algorithm for MRO in python.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With