Reputation: 30216
So it seems I'm misunderstanding some basic stuff about Python. Passing an instance variable into a function should only pass a reference to the object itself, so in case the object is immutable doing something like self.var = "something"; foo(self.var)
shouldn't change self.var if foo assigned a new value to the variable - so long everything's fine and as expected.
But now consider this:
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)
I create a thread object with a reference to the current string and afterwards update it - which the thread shouldn't see. Thanks to the lock the next thread also should only start after the update - so while I can't make any assumptions about the sequence in which arg0-5 will be printed I'd assume every arg should be printed exactly once. But I get the following output (Win7 x64, python 3.1 x64)
Bar: arg0
Bar: arg2
Bar: arg2
Bar: arg5
Bar: arg3
Edit: Okay after typing this up, I had the glorious idea that probably the lambda expression isn't executed when creating the thread but later on, which would explain the behavior, so the simple workaround would be to just create a local variable and use that. Well - now that was fast help by SO ;)
Upvotes: 2
Views: 1636
Reputation: 30216
Since I noticed I still hadn't answered that one, here we go:
The lambda creates a closure to self
but not to self.arg
itself, which means when we later execute bar we access the newest value and not the one at lambda creation time.
Upvotes: 2