假设我有一个清单:
L = [1,2,3]
我分配L[0]
给一个变量a
a = L[0]
那么如果我改变a
,它不会影响L
。
a = a + 1
print L # [1,2,3] not affected
为什么会这样?python 不是用引用传递所有东西吗?我以为a
那是指向L[0]
问题是a
andL[0]
是对不可变对象的引用,因此更改其中任何一个都不会影响其他引用:
>>> L = [1, 2, [3]]
>>> a = L[0]
>>> a = a + 1
a
现在指向一个新对象,同时L[0]
仍然指向同一个对象。
>>> a, L[0]
(2, 1)
现在在这种情况下b
,并且L[2]
是对可变对象(list
)的引用,对它们的任何就地操作都会影响所有引用:
>>> b = L[2]
>>> b.append(4) #list.append is an in-place operation
>>> b, L[2]
([3, 4], [3, 4])
>>> b = b + [5] #mutable object, but not an in-place operation
>>> b #b is assigned to new list object
[3, 4, 5]
>>> L[2] #L[2] is unchanged
[3, 4]
L[0]
是一个名称,当您创建 list 时L
,您将一个对象分配给该名称,整数 1. a
也是一个名称,并且当您分配 a as in 时a = L[0]
,您使a
指向指向的同一个对象L[0]
。
但是当你以后做的时候a = a + 1
,这是另一个任务。您没有修改a
指向的对象——=
标志不能这样做。您正在创建一个新对象,即整数 2,并将其分配给a
.
所以最后,你在内存中有两个对象;一个被 引用,L[0]
另一个被 引用a
。
整数是不可变的,这意味着在此示例中无法更改对象的属性;然而,这在这个例子中并不明显,因为即使对象是可变的,它也不会改变你正在做赋值的事实(带有=
符号)。在所讨论的对象是可变的情况下,理论上您可以在对象仍然被L[0]
and引用时更改对象的属性,而不是像您所做的那样a
进行任何额外的赋值。=
此时,无论您使用哪个名称检查对象,您都会看到属性发生变化。
由于L[0]
在您的情况下是不可变的,因此更改a
不会影响L[0]
. 当你改变a
时,新对象被创建并a
开始指向它。
看看如果L[0]
是可变类型会发生什么:
>>> L = [[1],2,3]
>>> a = L[0]
>>> a.append(2)
>>> L
[[1, 2], 2, 3]
在这种情况下a
,L[0]
两者都指向同一个对象。
另请参阅Raymond Hettinger在相关线程中的回答。
将分配更改为:
a = L
然后当您将 L 更改为:
L[0] += 1
你会看到 a 也发生了变化。这是参考魔法。