Based on your toy example here is one way to do it.
class FooBase:
def foo(self):
self.bar()
class FooMod:
def foo(self):
print("hi")
self.bar()
class A(FooBase):
def bar(self):
print("A bar")
class B(FooBase):
def bar(self):
print("B bar")
class C(FooBase):
def bar(self):
print("C bar")
class ModA(FooMod,A):
pass
class ModB(FooMod,B):
pass
class ModC(FooMod,C):
pass
class BadModA(A,FooMod):
pass
for thing in [A,B,C,ModA,ModB,ModC,BadModA]:
thing = thing()
print(thing.foo())
print('**********')
You have to be careful how you order the base classes notice BadModA doesn't work because it finds the foo method in FooBase before looking in FooMod. You can see that in their Method Resolution Order's
In [15]: ModA.__mro__
Out[15]: [__main__.ModA, __main__.FooMod, __main__.A, __main__.FooBase, object]
In [16]: BadModA.__mro__
Out[16]: (__main__.BadModA, __main__.A, __main__.FooBase, __main__.FooMod, object)
While this works it seems like you could get yourself in trouble. you always have to remember which order to use - maybe someone will comment.
Here is another way, it flattens the structure out a bit, five bases and you mix them up
class FooBase:
def foo(self):
self.bar()
class FooMod:
def foo(self):
print("hi")
self.bar()
class Abar:
def bar(self):
print("A bar")
class Bbar:
def bar(self):
print("B bar")
class Cbar():
def bar(self):
print("C bar")
class A(FooBase,Abar):
pass
class B(FooBase,Bbar):
pass
class C(FooBase,Cbar):
pass
class ModA(FooMod,Abar):
pass
class ModB(FooMod,Bbar):
pass
class ModC(FooMod,Cbar):
pass