Python: threading.Thread, 值是传值还是传引用?
Python: threading.Thread, are values passed by value or reference?
我将值 i 传递给 th = threading.Thread(target=func, args=(i,))
并在 th.start()
前立即启动线程。
因为这是在索引 i 不断变化的循环中执行的,所以我想知道线程中的 i 是否保留了线程创建时的值,或者线程是否正在处理 i 的引用。在后一种情况下,价值不一定与创建时的价值相同。
值是通过引用还是值传递的?
按值传递和按引用传递这两个术语有时会产生误导,而且它们在每种语言中的含义并不总是相同。我假设我们正在研究这两个术语在 C 中的含义(其中引用将指针传递给变量)。
Python其实两者都不是,我给你举一个我从一篇文章中摘录的例子(感谢原作者,我将link文章放在最后)
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
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 是一种 "pass-by-reference" 编程语言,那么 foobar(a)
调用可能会导致该程序通过将局部变量 a
更改为来打印 Impossible!
引用一些不同的对象。
但是,Python 不进行引用传递。它只按值传递,这意味着没有 foobar
的定义可以使片段执行 print
调用。 foobar
函数可以改变局部变量 a
引用的对象,但它不能修改 a
本身。
我将值 i 传递给 th = threading.Thread(target=func, args=(i,))
并在 th.start()
前立即启动线程。
因为这是在索引 i 不断变化的循环中执行的,所以我想知道线程中的 i 是否保留了线程创建时的值,或者线程是否正在处理 i 的引用。在后一种情况下,价值不一定与创建时的价值相同。
值是通过引用还是值传递的?
按值传递和按引用传递这两个术语有时会产生误导,而且它们在每种语言中的含义并不总是相同。我假设我们正在研究这两个术语在 C 中的含义(其中引用将指针传递给变量)。
Python其实两者都不是,我给你举一个我从一篇文章中摘录的例子(感谢原作者,我将link文章放在最后)
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
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 是一种 "pass-by-reference" 编程语言,那么 foobar(a)
调用可能会导致该程序通过将局部变量 a
更改为来打印 Impossible!
引用一些不同的对象。
但是,Python 不进行引用传递。它只按值传递,这意味着没有 foobar
的定义可以使片段执行 print
调用。 foobar
函数可以改变局部变量 a
引用的对象,但它不能修改 a
本身。