0

I came across a solution to selectively inherit classes. Though it is a good solution, I would like to create a wrapper Class instead of a class returned as a function. Specifically, in my case, because it's a bit more complex, I have the following:

class A(object):
    def __init__(self, argM, argO1=0, argO2=''):
        # do something here

    def funA(self):
        # do something here


class B(A):
    def __init__(self, argO1=0, argO2=''):
        super(B, self).__init__(argM, argO1=0, argO2='')
        # do something here

    def funB(self):
        # do something here


class C(B):
    def __init__(self, argM, argO1=0, argO2=''):
        super(C, self).__init__(argM, argO1=0, argO2='')
        # do something here

    def funC(self):
        # do something here


class D(C):
    def __init__(self, argM, argO1=0, argO2=''):
        super(D, self).__init__(argM, argO1=0, argO2='')
        # do something here

    def funD(self):
        # do something here


class E(C):
    def __init__(self, argM, argO1=0, argO2=''):
        super(E, self).__init__(argM, argO1=0, argO2='')
        # do something here

    def funE(self):
        # do something here


class F(C):
    def __init__(self, argM, argO1=0, argO2=''):
        super(F, self).__init__(argM, argO1=0, argO2='')
        # do something here

    def funF(self):
        # do something here


class G(B):
    def __init__(self, argM, argO1=0, argO2=''):
        super(G, self).__init__(argM, argO1=0, argO2='')
        # do something here

    def funG(self):
        # do something herehere


class H(B):
    def __init__(self, argM, argO1=0, argO2=''):
        super(H, self).__init__(argM, argO1=0, argO2='')
        # do something here

    def funG(self):
        # do something here

To create a wrapper class MyClass, I wrote the following function as described in the link above:

def createMyClass(argM, objdetails, fun1=0, fun2=0, fun3=0, sup1=0, sup2=0):  # fun1, fun2, fun3 are mutually exculsive.
    det1 = objdetails['argO1']
    det2 = objdetails['argO2']

    if fun1:
        class Cf1(C):
            def __init__(self):
                super(Cf1, self).__init__(argM, argO1=det1, argO2=det2)
        if sup1:
            class Cs1(G):
                def __init__(self):
                    super(Cs1, self).__init__(argM, argO1=det1, argO2=det2)
            if sup2:
                class Cs2(H):
                    def __init__(self):
                        super(Cs2, self).__init__(argM, argO1=det1, argO2=det2)
                class MyClass(Cf1, Cs1, Cs2):
                    def __init__(self):
                        super(MyClass, self).__init__()
            else:
                class MyClass(Cf1, Cs1):
                    def __init__(self):
                        super(MyClass, self).__init__()
        else:
            class MyClass(Cf1):
                def __init__(self):
                    super(MyClass, self).__init__()

    if fun2:
        class Cf1(D):
            def __init__(self):
                super(Cf1, self).__init__(argM, argO1=det1, argO2=det2)
        if sup1:
            class Cs1(G):
                def __init__(self):
                    super(Cs1, self).__init__(argM, argO1=det1, argO2=det2)
            if sup2:
                class Cs2(H):
                    def __init__(self):
                        super(Cs2, self).__init__(argM, argO1=det1, argO2=det2)
                class MyClass(Cf1, Cs1, Cs2):
                    def __init__(self):
                        super(MyClass, self).__init__()
            else:
                class MyClass(Cf1, Cs1):
                    def __init__(self):
                        super(MyClass, self).__init__()
        else:
            class MyClass(Cf1):
                def __init__(self):
                    super(MyClass, self).__init__()

    if fun3:
        class Cf1(E):
            def __init__(self):
                super(Cf1, self).__init__(argM, argO1=det1, argO2=det2)
        if sup1:
            class Cs1(G):
                def __init__(self):
                    super(Cs1, self).__init__(argM, argO1=det1, argO2=det2)
            if sup2:
                class Cs2(H):
                    def __init__(self):
                        super(Cs2, self).__init__(argM, argO1=det1, argO2=det2)
                class MyClass(Cf1, Cs1, Cs2):
                    def __init__(self):
                        super(MyClass, self).__init__()
            else:
                class MyClass(Cf1, Cs1):
                    def __init__(self):
                        super(MyClass, self).__init__()
        else:
            class MyClass(Cf1):
                def __init__(self):
                    super(MyClass, self).__init__()

    return MyClass

This can be used to create a wrapper class by calling:

obj1 = {'argO1': 0, 'argO2': 'Batter'}
C1 = createMyClass("First", obj1, fun1=1, sup1=1)
obj2 = {'argO1': 0, 'argO2': 'Pitcher'}
C2 = createMyClass("Starting", obj2, fun2=1, sup1=1, sup2=1)

But I would like to replace the function createMyClass with a class MyClass with a responsibility of simply do the functionality of selective inheritance and no other methods/functions. So that I can do:

obj1 = {'argO1': 0, 'argO2': 'Batter'}
C1 = MyClass("First", obj1, fun1=1, sup1=1)
obj2 = {'argO1': 0, 'argO2': 'Pitcher'}
C2 = MyClass("Starting", obj2, fun2=1, sup1=1, sup2=1)

How can I do this?

skrowten_hermit
  • 437
  • 3
  • 11
  • 28
  • What would be the difference between using the function and the class? The syntax is exactly the same, and `MyClass` will have to sneakily substitute itself for a different class object to account for different bases anyway, so it'll do exactly the same as the function too. – ForceBru Jun 23 '20 at 17:14
  • @ForceBru Very true, agreed. I am just being curious. The first time I faced a situation where I had to conditionally inherit. I thought a wrapper class sounds more fancier than a function that returns a class. and probably is more scalable. I wanted to learn if there is a way, just to know. Tried my hand with `__new__`, couldn't succeed. Any pointers would be helpful. – skrowten_hermit Jun 23 '20 at 17:21
  • In Python 3 you can simply move the `createMyClass` function into `MyClass.__new__` and make `MyClass(arg, arg)` return whatever class you want, but Python 2 will attempt to initialise these classes, I think, and say `TypeError: this constructor takes no arguments` when the only function in the class is `def __new__(cls, a):` and you try to initialise the class like `Test(5)`. It doesn't even call `Test.__new__`... – ForceBru Jun 23 '20 at 17:47
  • You're right. `__new__` is not even called on instantiation. Any print statement in `__init__` is executed, as expected. But `__new__` doesn't. Does this mean Python 2.7 doesn't support this? – skrowten_hermit Jun 23 '20 at 19:06
  • Ah, your class should be a [new-style class](https://www.python.org/doc/newstyle/) for this to work: https://stackoverflow.com/a/31772581/4354477 – ForceBru Jun 23 '20 at 19:35

0 Answers0