1

假设我有一个清单:

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]

4

4 回答 4

3

问题是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]
于 2013-09-25T06:40:49.530 回答
2

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进行任何额外的赋值。=此时,无论您使用哪个名称检查对象,您都会看到属性发生变化。

于 2013-09-25T06:45:29.530 回答
1

由于L[0]在您的情况下是不可变的,因此更改a不会影响L[0]. 当你改变a时,对象被创建并a开始指向它。

看看如果L[0]是可变类型会发生什么:

>>> L = [[1],2,3]
>>> a = L[0]
>>> a.append(2)
>>> L
[[1, 2], 2, 3]

在这种情况下aL[0]两者都指向同一个对象。

另请参阅Raymond Hettinger相关线程中的回答。

于 2013-09-25T06:37:25.043 回答
0

将分配更改为:

a = L

然后当您将 L 更改为:

L[0] += 1

你会看到 a 也发生了变化。这是参考魔法。

于 2013-09-25T06:52:29.470 回答