Python: threading.thread, значения передаются по значению или по ссылке?

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

На самом деле, ни то, ни другое - переменные Python не являются символическими именами для ячеек памяти (как в C или Pascal и т.д.), а являются привязками «name => object», поэтому ни одна из концепций «по значению» или «по ссылке» не применима. Вы определенно хотите прочитать это, чтобы понять «переменные» Python: nedbatchelder.com/text/names.html

bruno desthuilliers 31.10.2018 12:12

Re: «... я внутри потока ...» У потока нет «внутри». Функция target имеет внутреннюю часть (т.е. ее формальные аргументы и локальные переменные), но она такая же, как и у любой другой функции. Это не потому, что функция является target потока.

Solomon Slow 31.10.2018 14:00

@SolomonSlow конечно, это то, о чем я говорю;)

dlsf 31.10.2018 14:56

К настоящему времени я проверил несколько случаев, и, похоже, использование целевой функции многопоточности соответствует определению обычной функции. Итак, что действительно имеет значение, так это то, является ли объект («переменная») изменяемым или неизменяемым. Если он изменяемый (например, список), то на языке C мы работаем с указателем. Если он неизменяемый, переменная вызывается по значению.

dlsf 31.10.2018 15:14
0
5
2 330
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Передача по значению и передача по ссылке - это два термина, которые иногда могут вводить в заблуждение, и они не всегда означают одно и то же на всех языках. Я предполагаю, что мы принимаем во внимание значение этих двух терминов в 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. Этот бит больше похож на передачу по значению.

РЕДАКТИРОВАТЬ

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

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

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

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

Re: «Python на самом деле ни то, ни другое» и «... два термина, которые могут вводить в заблуждение ...» Это только вводит в заблуждение людей, которые не полностью понимают разницу между объектом, выделенным в куче, и переменной, которая относится к объект, размещенный в куче. Как только ученик узнает эту разницу, становится очевидным, что аргументы вызова функции Python всегда передаются по значению.

Solomon Slow 31.10.2018 13:54

«Тем не менее, учитывая, что i - это индекс цикла в вашем примере; он будет изменен, если вы, например, добавите к нему 1. Исходный поток также будет иметь новое значение». Я тестировал его сейчас, и это не правда. Поскольку i неизменяем, как только он передается целевой функции потока, например после th = threading.Thread(target=func, args=(i,)) значение i внутри целевой функции больше не связано с "внешним".

dlsf 31.10.2018 15:07

@SolomonSlow Не могли бы вы прояснить, как это связано с изменяемыми / неизменяемыми объектами? Потому что я бы сказал, что передача изменяемых объектов функциям вызывается по ссылке. Являются ли объекты, выделенные кучей, неизменяемыми, а переменные, относящиеся к объектам, выделенным кучей, изменяемыми?

dlsf 31.10.2018 15:27

Ты прав @dlsf. Но это не потому, что он становится изменяемым, когда вы создаете поток. Это потому, что целые числа Python неизменны по своей природе. Из-за этого вы не можете изменить i, который живет в вашем потоке, просто назначьте ему новый объект. Если вы передали какой-либо изменяемый объект, например список (или, возможно, изменяемую оболочку для int), он изменился бы. Я отредактирую свой ответ, как только смогу это объяснить.

Pablo Paglilla 31.10.2018 16:03
Ответ принят как подходящий

I would say, passing mutable objects to functions is calling by reference.

Не только вы хотите сказать это, но такое мышление ограничивает вашу способность общаться с другими о том, как на самом деле работают программы 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

Другие вопросы по теме