Search code examples
pythonmultithreadingclassinheritancetarget

How could I give a inherited class function to a thread?


import threading
class A:
    def func(self):
        print('asdf')

class B(A):
    def func(self):
        print('1234')

class C(A):
    def func(self):
        print('xyzw')
def f(inner_func):
    class_list = [A(),B(),C()]
    thread_list = []
    for i in class_list:
        x=threading.Thread(target=inner_func(i,),args=())
        thread_list.append(x)
        x.start()
    for i in thread_list:
        i.join()
f(A.func)

I thought this would print

asdf
1234
xyzw

but it just prints

asdf
asdf
asdf

How can I use the inherited classes' functions at once, without doing it manually? I want to give the inner_func with an argument, so I could use it with different functions. For example, if class A,B,C had another function func2, I could use it as f(A.func2) or something like that.


Solution

  • In your code, each thread is executing A.func with self set to an instance of A, B and C. In no case does it access B.func or C.func. There is no possible object in Python that refers to A.func or B.func or C.func depending on the context.

    What you need to do instead is pass the name of the function you wish to execute, then retrieve the appropriate function from the desired instance or class. So, the last call needs to be f("func"); the function f needs to be changed appropriately. Specifically, you can use getattr(A, 'func') to get the unbound method (which you could then invoke as method(A())), or you can use getattr(A(), 'func') to get a bound method (which you could invoke as method()).

    (Also, off-topic, but using i for both threads and instances is super confusing, as is naming a list of instances class_list.)

    def f(method_name):
        instance_list = [A(), B(), C()]
        thread_list = []
        for instance in instance_list:
            thread = threading.Thread(target=getattr(instance, method_name), args=())
            thread_list.append(thread)
            thread.start()
        for thread in thread_list:
            thread.join()
    
    f('func')