Python: threading.Thread, значения передаются по значению или по ссылке? - PullRequest
0 голосов
/ 31 октября 2018

Я передаю значение i в th = threading.Thread(target=func, args=(i,)) и сразу же запускаю поток на th.start(). Поскольку это выполняется внутри цикла с изменением индекса i, мне интересно, сохраняет ли i внутри потока свое значение с момента создания потока, или же поток работает по ссылке на i. В последнем случае значение не обязательно будет таким же, как при создании th. Передаются ли значения по ссылке или по значению?

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Я бы сказал, что передача изменяемых объектов в функции - это вызов по ссылке.

Вы не одиноки в желании сказать это, но такое мышление ограничивает вашу способность общаться с другими о том, как на самом деле работают программы на Python.

Рассмотрим следующий фрагмент Python:

a = [1, 2, 3]
b = a
foobar(a)
if not b is a:
    print('Impossible!')

Если бы Python был языком программирования с передачей по ссылке, то вызов foobar(a) мог заставить эту программу печатать Impossible!, изменяя локальную переменную a для ссылки на какой-то другой объект.

Но Python не выполняет передачу по ссылке. Он только передает по значению, и это означает, что нет определения foobar, которое могло бы заставить фрагмент выполнить вызов print. Функция foobar может мутировать объект, на который ссылается локальная переменная a, но она не может изменять сам a.

См. https://en.wikipedia.org/wiki/Evaluation_strategy

0 голосов
/ 31 октября 2018

Передача по значению и передача по ссылке - это два термина, которые иногда могут вводить в заблуждение, и они не всегда означают одно и то же в каждом языке. Я собираюсь предположить, что мы понимаем, что означают два термина в C (где ссылка передает указатель на переменную).

Python на самом деле ни один из них, я приведу вам пример, который я взял из статьи (все благодарности оригинальному писателю, я свяжу статью в конце)

def spam(eggs):
    eggs.append(1)
    eggs = [2, 3]

ham = [0]
spam(ham)
print(ham)

Когда вызывается spam, и ham, и eggs указывают на одно и то же значение ([0]) на один и тот же объект. Таким образом, когда eggs.append (1) выполняется, [0] становится [0, 1]. Это звучит как передача по ссылке.

Однако, когда eggs = [2, 3], теперь и eggs, и ham должны стать новым списком при передаче по ссылке. Но этого не происходит; теперь eggs указывает на список в памяти, содержащий [2, 3], но ham по-прежнему указывает на исходный список с добавленной к нему 1. Этот бит больше похож на проход по значению.

EDIT

Как объяснено выше, если параметр потока изменяется внутри него, изменения будут видны в исходном потоке, пока параметр является изменяемым. Таким образом, передача списка потоку и добавление чего-либо к нему будет отражено, например, в потоке вызывающего.

Однако неизменный объект нельзя изменить. Если вы делаете i += 1, вы не изменяете целое число, целые числа неизменны в Python. Вы присваиваете i новое целое число со значением на единицу выше, чем предыдущее. Это то же самое, что случилось с eggs = [2, 3]. Таким образом, в этом конкретном примере изменения не будут отражены в исходной ветке.

Надеюсь, это поможет!

Вот статья, которую я обещал, она гораздо лучше объясняет этот вопрос. http://stupidpythonideas.blogspot.com/2013/11/does-python-pass-by-value-or-by.html?m=1

...