Daniel Azemar
Daniel Azemar

Reputation: 565

Choose which parent class inherit from in Python

I'm struggling into trying to choose the parent class to inherit from when creating a class without affecting any children classes.

There's a pyramidal structure of classes where, on the top, I try to choose where to inherit from: threading.Thread or multiprocessing.Process (specifying it with an argument on the children classes).

I've managed to do it only with the first level of this pyramid creating a function that returns the Base Class, code here:

class ProcessClass(object):
    '''A thread with different inheritance.
    '''
    def __new__(cls, *args, **kwargs):
        thr_type = kwargs.pop("thr_type","threading")
        print("HELLO", thr_type)
        if(thr_type == "threading"):
            new_cls = threading.Thread 
        if(thr_type == "multiprocessing"):
            new_cls = multiprocessing.Process
        instance = super(ProcessClass, cls).__new__(obtain_thread_class(new_cls))
        instance.__init__(*args, **kwargs)
        return instance

def obtain_thread_class(new_cls):
    class BaseClass(new_cls):
        """Class with its methods"""
        def __init__(self, daemon=False, *args, **kwargs):
            # THREADING
            super(BaseClass, self).__init__(*args, **kwargs)
            self.daemon=daemon
        def hello(self):
            print("Hello World")
    return BaseClass

But now, when I try to inherit ProcessClass in a child class, this one looses all his properties, and the parameters can not be passed properly (i think this is due __new__).

The child example class is:

class ExampleClass(ProcessClass):
    def __init__(self, arg1, arg2, arg3="1", *args, **kwargs):
        self.list_args = [arg1, arg2]
        print("arg3 is", arg3)
        super(ExampleClass, self)
    def hello2(self):
        print("Hello from child!")

With this, if I execute:

a = ExampleClass(thr_type="threading")
print(type(a))

I obtain:

HELLO threading
<class '__main__.obtain_thread_class.<locals>.BaseClass'>

But then, i can only call hello() but not hello2():

a.hello()
Hello World

a.hello2()
Traceback (most recent call last):

  File "<ipython-input-11-2505bb83de52>", line 1, in <module>
    a.hello2()

AttributeError: 'BaseClass' object has no attribute 'hello2'

I think using __new__ is the thing that is breaking children creation.

I've tried using also decorators, and seen something of __metaclasses__ but before getting in deeper in those realms, I would like to know if there's something easier since I'm not that expert in python.

Also, I don't want this change to affect any of the program I'm running already, (many classes are inheriting from ProcessClass, but this is only threading.Thread by the moment). I'm trying to keep this change unnoticiable for the overall programs.

Upvotes: 0

Views: 817

Answers (1)

Daniel Azemar
Daniel Azemar

Reputation: 565

Finally i went with composition. Did not found how to choose inheritance in runtime. But this still works.

class ProcessClass(object):
    '''A thread with different inheritance.
    '''
    def __init__(self, thr_type="multiprocessing", *args, **kwargs):
        if(thr_type == "threading"):
            new_cls = threading.Thread
        if(thr_type == "multiprocessing"):
            new_cls = multiprocessing.Process
        self.thread = new_cls(*args, **kwargs)
    def start(self):
        return self.thread.start()

    def run(self):
        return self.thread.run()

Upvotes: 0

Related Questions