假设我有一个清单:
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]
问题是aandL[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 也发生了变化。这是参考魔法。