In my code, I have the inheritance relation B -> C -> D
, and there is a particular function f
of interest here
class C(B):
def f(self):
if <some condition>:
B.f(self)
else:
<do other stuff>
And the issue is that there are multiple possibilities of B
in reality, but the logic of C
is the same. A straightforward way is then to use linear inheritance multiple times, i.e.,
B1 -> C1 -> D1
B2 -> C2 -> D2
B3 -> C3 -> D3
However, it is wasteful. Then I am thinking of using multiple inheritance
D1(C, B1)
D2(C, B2)
D3(C, B3)
Then the problem is how does C.f()
access B1.f()
(same for B2
, B3
) since it only knows the existence of B1
via D1
?
Is this a bad idea to use multiple inheritance in this case? Or is there a better way than both the straightforward linear inheritance with multiple C
s and multiple inheritance (if it works)?
That is a classic problem on multiple-inheritance that ultimately led some languages to opt-out from multiple-inheritance at all.
Python however, got away just by putting in place a cleverly crafted "method resolution order" (mro) algorithm, and later, with the advent of the super
built-in call. The algorithm and its history are detailed in https://www.python.org/download/releases/2.3/mro/
But, long history short, it just works as expected "by heart". For example, by pasting this code on the interactive interpreter:
class A: pass
class B(A):
def f(self): raise NotImplementedError
class C(B):
def f(self):
super().f()
print("C")
class B1(B): f = lambda s: print("B1")
class B2(B): f = lambda s: print("B2")
class D(C, B1): pass
class D1(C, B2): pass
We get these results when tinkering along:
In [25]: D().f()
B1
C
In [26]: D1().f()
B2
C
In [27]: D.__mro__
Out[27]: (__main__.D, __main__.C, __main__.B1, __main__.B, __main__.A, object)