First of all, I have to apologize for not having a better title. Feel free to change it if you find a more appropriate one.
Basically, I have been bugged by the behaviour of Python's multiple inheritance. In my previous SO question, I got directed to read Python's C3 MRO. That really helps me to have a better understanding of multiple inheritance in Python. Just when I thought I got the grasp of it, I bumped into the following scenario, which I can't seem to make sense of.
class UltimateBase(object):
def check(self):
print 'base check'
class AMixin1(UltimateBase):
def check(self):
print 'check A'
class BMixin1(UltimateBase):
def check(self):
print 'check B'
class CMixin1(UltimateBase):
def check(self):
print 'check C'
class AMixin2(UltimateBase):
def check(self):
print 'check A'
return super(AMixin2, self).check()
class BMixin2(UltimateBase):
def check(self):
print 'check B'
return super(BMixin2, self).check()
class CMixin2(UltimateBase):
def check(self):
print 'check C'
return super(CMixin2, self).check()
class MyView1(AMixin1, BMixin1, CMixin1):
pass
class MyView2(AMixin2, BMixin2, CMixin2):
pass
class MyView3(AMixin1, BMixin2, CMixin2):
pass
class MyView4(AMixin2, BMixin1, CMixin2):
pass
class MyView5(AMixin2, BMixin2, CMixin1):
pass
class MyView6(AMixin1, BMixin1, CMixin2):
pass
class MyView7(AMixin1, BMixin2, CMixin1):
pass
class MyView8(AMixin2, BMixin1, CMixin1):
pass
myview1 = MyView1()
myview2 = MyView2()
myview3 = MyView3()
myview4 = MyView4()
myview5 = MyView5()
myview6 = MyView6()
myview7 = MyView7()
myview8 = MyView8()
myview1.check()
print '------------------------'
myview2.check()
print '------------------------'
myview3.check()
print '------------------------'
myview4.check()
print '------------------------'
myview5.check()
print '------------------------'
myview6.check()
print '------------------------'
myview7.check()
print '------------------------'
myview8.check()
print '------------------------'
Outputs:
check A
------------------------
check A
check B
check C
base check
------------------------
check A
------------------------
check A
check B
------------------------
check A
check B
check C
------------------------
check A
------------------------
check A
------------------------
check A
check B
------------------------
I can trace out a pattern based on observing the outputs, but it bugs me not understanding the rationale behind this result.
I have questions like, for example, why does myview2.check()
return
check A
check B
check C
base check
not
check A
base check
It seems to me that I am missing a key piece about multiple inheritance. Please fill in the gap for me.
The super() function is used to give access to methods and properties of a parent or sibling class. The super() function returns an object that represents the parent class.
The diamond problem is an ambiguity that is arisen when there are two classes say B and C that inherit / are derived from a single class A, and there is another class D, that is a class derived from multiple inheritance and inherits from B as well as C.
Python | super() in single inheritance. At a fairly abstract level, super() provides the access to those methods of the super-class (parent class) which have been overridden in a sub-class (child class) that inherits from it.
Supercharge Your Classes With Python super()Python supports inheritance from multiple classes.
When you call myview2.check()
, it traverses siblings then calls the base class. Whenever one of those traversals hits AMixin1
, BMixin1
, or CMixin1
, it stops, because those classes do not call super(..., self).check()
.
As Benn points out, this is described in the official Python documentation. And if you think about it, it pretty much has to work this way. Subclasses are going to assume the base class method isn't called before the subclass calls super()
. If it is (or, worse, if it depends on the order its siblings are listed), it makes things very difficult to deal with.
Tried to get my head round the same question. I found the following code helped simplify the issue:
(Basically, when all the super
s have been hit for a class, that class gets called.)
class A:
def f(self):
print("............A: the common base of B and C")
class B(A):
def f(self):
print("........B: the left base of D")
super().f()
class C(A):
def f(self):
print("........C: the right base of D")
super().f()
class D(B,C):
def f(self):
print("....D: the top class")
super().f()
d = D()
d.f()
Output:
....D: the top class
........B: the left base of D
........C: the right base of D
............A: the common base of B and C
Try Online
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