Earlier I had a simple single-inheritance architecture between two classes C1 and C2, which worked well:
class C1:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        print("C1")
class C2(C1):
    def __init__(self, z, *args):
        C1.__init__(self, *args)
        self.z = z
        print("C2")
c2 = C2(1, 2, 3) # prints "C1" and "C2"
print(c2.x, c2.y, c2.z) # prints 2 3 1
Now the architecture has become more complicated:
class _B1: # abstract base
    def __init__(self, x):
        self.x = x
        print("B1")
class _B2(_B1): # concrete base
    def __init__(self, z, *args):
        _B1.__init__(self, *args)
        self.z = z
        print("B2")
class _M1: # abstract mixin
    def __init__(self, y):
        self.y = y
        print("M1")
class _M2(_M1): # concrete mixin
    def __init__(self, *args):
        _M1.__init__(self, *args)
        print("M2")
class C1(_M1, _B1): # abstract composed
    def __init__(self, x, y): # old signature must not be changed
        _B1.__init__(self, x)
        _M1.__init__(self, y)
        print("C1")
class C2(_M2, _B2, C1): # concrete composed; use C1 here because isinstance(c2, C1) must still return True
    def __init__(self, z, *args): # old signature must not be changed
        C1.__init__(self, *args) # works
        _B2.__init__(self, z, x) # Problem 1a: cannot do that because x is abstracted in *args
        _M2.__init__(self, y) # Problem 1b: cannot do that because y is abstracted in *args
        # Problem 2: there seem to be "two versions" of B1 and M1 (one from C1 and one from B2 or M2, resp.), and so the constructors are each called twice
        print("C2")
# c2 = C2(1, 2, 3)
# print(c2.x, c2.y, c2.z)
As stated in the code, I cannot figure out how to pass the arguments to the constructors. Also the fact that the constructors are called twice gives me the feeling that this is a bad design; however, from an OOP perspective, I could not think of a more accurate one.
I am aware of some workarounds, but I would prefer a canonical solution. In particular, I would not want to include x and y in C2.__init__.
 
    