Python 实例变量的线程问题

Python 实例变量的线程问题,python,multithreading,thread-safety,python-3.x,Python,Multithreading,Thread Safety,Python 3.x,所以我似乎误解了Python的一些基本内容。将实例变量传递到函数中应该只传递对对象本身的引用,因此在对象不可变的情况下,可以执行类似于self.var=“something”的操作;foo(self.var)如果foo给变量分配了一个新的值,就不应该更改self.var——只要一切正常并且符合预期 但现在考虑一下: import threading class Test(): def __init__(self): self.lock = threading.Lock(

所以我似乎误解了Python的一些基本内容。将实例变量传递到函数中应该只传递对对象本身的引用,因此在对象不可变的情况下,可以执行类似于
self.var=“something”的操作;foo(self.var)
如果foo给变量分配了一个新的值,就不应该更改self.var——只要一切正常并且符合预期

但现在考虑一下:

import threading

class Test():
    def __init__(self):
        self.lock = threading.Lock()
        self.arg = "arg0"

    def foo(self, i):
        with self.lock:
            threading.Thread(target=lambda: bar(self.arg)).start()
            self.arg = "arg" + str(i)

def bar(arg):
    import time
    time.sleep(1)
    print("Bar: " + arg)

if __name__ == '__main__':
    t = Test()
    for i in range(1, 6):
        t.foo(i)
我创建了一个线程对象,引用了当前字符串,然后更新了它——线程不应该看到它。多亏了锁,下一个线程也应该只在更新后启动——因此,虽然我不能对arg0-5的打印顺序做出任何假设,但我会假设每个arg都应该精确打印一次。但是我得到了以下输出(win7x64,python3.1x64)


编辑:好的,在输入这个之后,我有了一个很好的想法,创建线程时可能不会执行lambda表达式,但稍后会执行,这将解释行为,因此简单的解决方法是只创建一个局部变量并使用它。好吧,这是苏的快速帮助;)

因为我注意到我还没有回答这个问题,我们开始:


lambda创建了一个对
self
的闭包,而不是对
self.arg
本身的闭包,这意味着当我们稍后执行bar时,我们访问的是最新的值,而不是lambda创建时的值。

恭喜!你解开了这个谜。另一件事:你认为
类测试():
做什么,而不是
类测试:
类测试(对象):
?@pillmuncher:我使用的是Python3,所以幸运的是,我不必担心旧类和新类。虽然我不知道
类测试:
是合法语法-这样更好一些,很棒(对于python2来说,它仍然默认为旧的类语法,不是吗?@Voo如果你解决了自己的问题,把它作为答案发布,两天后你就可以接受它了。
Bar: arg0
Bar: arg2
Bar: arg2
Bar: arg5
Bar: arg3