I have the following classes defined:
class A(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = ""
def mA1(self):
print "Method 1 in A"
def mA2(self):
print "Method 2 in A"
def mA3(self):
print "Method 3 in A"
class B(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.x = 0
def mB1(self):
print "Method 1 in B"
class C(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = ""
self.y = 1
def mC1(self):
print "Method 1 in C"
def mC2(self):
print "Method 2 in C"
As it can be seen, they take the same input arguments in the constructor. Now, I want to create a class D
which inherits from all of A
, B
and C
so that I can directly pass the arguments to D
's constructor as follows:
clsT = D(1, 2)
So, I tried out as mentioned here the following revised definitions:
class A(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = ""
def mA1(self):
print "Method 1 in A"
def mA2(self):
print "Method 2 in A"
def mA3(self):
print "Method 3 in A"
class B(A):
def __init__(self, **kw):
super(B, self).__init__(**kw)
self.x = 0
def mB1(self):
print "Method 1 in B"
class C(A):
def __init__(self, **kw):
super(C, self).__init__(**kw)
self.c = ""
self.y = 1
def mC1(self):
print "Method 1 in C"
def mC2(self):
print "Method 2 in C"
class D(A, B, C):
def __init__(self, a, b):
super(D, self).__init__(a=a, b=b)
ci = D(1, 2)
print "a = ", ci.a
print "b = ", ci.b
print "c = ", ci.c
print "x = ", ci.x
print "y = ", ci.y
The above doesn't seem to work and gives me the following error:
class D(A, B, C):
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases B, C, A
What could possibly be going wrong? Is it really required that B
and C
must include super()
, creating a linear inheritance at the mid-level base classes? Is there an alternative to my interpretation? If not, how can mine be tweaked to make it work?
I changed the class defintion of D
as follows and it worked
class D(B, C, A):
def __init__(self, a, b):
super(D, self).__init__(a=a, b=b)
So the overall class will look like, (I removed the methods to keep the code short)
class A(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = ""
class B(A):
def __init__(self, **kw):
super(B, self).__init__(**kw)
self.x = 0
class C(A):
def __init__(self, **kw):
super(C, self).__init__(**kw)
self.c = ""
self.y = 1
class D(B, C, A):
def __init__(self, a, b):
super(D, self).__init__(a=a, b=b)
c = D(1, 2)
print(c.a, c.b, c.x, c.c, c.y)
The output will be
1 2 0 1
This is due to a rule in the MRO algorithm which says (More details in this answer here, but the gist is
a class always appears before its ancestor ("monotonicity")
Hence B and C needs to appear before A, since A is the ancestor of B and C
Or in other words:
D is inheriting from A,B and C. Because B and C already inherits from A, there is no way python now cannot determine what class to look methods up on first; either A, or B and C, if you use the old order of defining. D(A, B, C)