调用了不正确的对象方法

Incorrect object method is invoked

我有一个 python 文件,其中包含一个摘要 class 和几个子 class 。代码如下所示

# test.py

import threading
from abc import ABC, abstractmethod

class Job(object):
    def __init__(self, job_name):
        self.job_name = job_name

    def start(self):
        self.run()
        self.clean_up()

    @abstractmethod
    def run(self):
        pass

    @abstractmethod
    def clean_up(self):
        pass

class JobA(Job):
    def __init__(self):
        super().__init__('job_a')
        print('JobA constructed')

    def run(self):
        print('%s: run for %s' % (self.__str__(), self.job_name))

    def clean_up(self):
        print('%s: clean up for %s' % (self.__str__(), self.job_name))

class JobB(Job):
    def __init__(self):
        super().__init__('job_b')
        print('JobB constructed')

    def run(self):
        print('%s: run for %s' % (self.__str__(), self.job_name))

    def clean_up(self):
        print('%s: clean up for %s' % (self.__str__(), self.job_name))

if __name__ == '__main__':
    jobs = [JobA(), JobB()]
    threads = [threading.Thread(name=job.__str__(), target=lambda: job.start())  for job in jobs]
    print(threads)
    for t in threads:
        print('starting thread %s' % t.name)
        t.start()

这段代码的输出是

JobA constructed
JobB constructed
[<Thread(<__main__.JobA object at 0x1008a8f70>, initial)>, <Thread(<__main__.JobB object at 0x1008a8d90>, initial)>]
starting thread <__main__.JobA object at 0x1008a8f70>
<__main__.JobB object at 0x1008a8d90>: run for job_b
<__main__.JobB object at 0x1008a8d90>: clean up for job_b
starting thread <__main__.JobB object at 0x1008a8d90>
<__main__.JobB object at 0x1008a8d90>: run for job_b
<__main__.JobB object at 0x1008a8d90>: clean up for job_b

虽然为JobA和JobB的对象都构造了两个线程,但是只在JobB的对象上调用start()。

我希望对数组中的不同对象调用 start()。 这段代码有没有错误?

谢谢。

我的 python 版本是 Python 3.9.7(默认,2021 年 10 月 12 日,22:38:23)[Clang 13.0.0 (clang-1300.0.29.3)] on darwin

lambda 定义引用列表理解的循环变量 job (即它定义了一个闭包)。当调用 lambda 时,它将解析名称 job,它现在指的是理解的 last 元素(即作业 B)。

相反,您可以使用默认值,以便将理解的每个对象正确绑定到相应的 lambda 函数:

threads = [threading.Thread(name=job.__str__(), target=lambda j=job: j.start())  for job in jobs]

考虑以下示例代码以获得更好的可视化效果:

>>> funcs = [lambda: print(x) for x in range(3)]
>>> for f in funcs:
...     f()
... 
2
2
2
>>> funcs = [lambda y=x: print(y) for x in range(3)]
>>> for f in funcs:
...     f()
... 
0
1
2