Потоковая проблема с переменными экземпляра - PullRequest
1 голос
/ 13 августа 2011

Так что, похоже, я неправильно понимаю некоторые базовые вещи о Python.Передача переменной экземпляра в функцию должна передавать только ссылку на сам объект, поэтому, если объект неизменен, выполнение чего-то вроде self.var = "something"; foo(self.var) не должно изменять self.var, если foo назначил новое значение переменной - до тех пор, пока всенормально и как и ожидалось.

Но теперь рассмотрим это:

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, я бы предположил, что каждый аргумент должен быть напечатан ровно один раз.Но я получаю следующий вывод (Win7 x64, python 3.1 x64)

Bar: arg0
Bar: arg2
Bar: arg2
Bar: arg5
Bar: arg3

Редактировать: Хорошо, после ввода этого текста, у меня была великолепная идея, что, вероятно, лямбда-выражение не выполняется при создании потока, нопозже, который объяснил бы поведение, поэтому простым обходным путем было бы просто создать локальную переменную и использовать ее.Хорошо - теперь это была быстрая помощь SO;)

1 Ответ

2 голосов
/ 20 мая 2012

Поскольку я заметил, что до сих пор не ответил, вот так:

Лямбда создает замыкание для self, но не для self.arg, что означает, что когда мы позже выполняем bar, мыполучить доступ к новейшему значению, а не к значению во время создания лямбды.

...