如果我有以下列表:
a = [1, 2, 3]
我运行以下代码:
for x in a:
x += 1
看来这并没有改变列表a
。
但是,如果我执行以下操作:
for i in range(0, len(a)):
a[i] += 1
这将修改“a”的内容。
所以我猜想x
并以不同的方式a[i]
指代元素。a
究竟是什么导致了这种差异?它们各自是如何引用的元素的a
?
当你遍历一个列表时,每个元素都会依次产生。但是,有不同种类的对象。 可变和不可变。当您执行以下操作时:
a += 1
对于不可变对象,它大致转换为:
a = a + 1
现在在这种情况下,您通过 获取对象引用a
,将 1 添加到它以创建一个新对象。然后为该新对象分配名称a
。请注意,如果我们在迭代时这样做,我们根本不会触及列表——我们只是不断地创建新对象并将它们分配给 name a
。
这对于可变对象是不同的。然后a += 1
居然就地改变了对象。因此,列表将看到更改,因为它所持有的对象已更改(突变)。(对于不可变对象,列表中包含的对象没有改变,因为它不可能)。有关更多信息,请参阅此问题。
这也使您在按索引迭代时更清楚地知道发生了什么。您构造了一个新整数并将其放入列表中(忘记之前该插槽中的任何内容)。
当你说,
for x in [1,2,3]:
x+=1
您是说,暂时将 x 保存为变量,然后在该临时保存中添加一个。当您进行下一次迭代时,垃圾人会破坏该变量,因为它是临时的。x 不是列表中的位置。它是列表中该位置的值。
编辑:当我说它被删除时,我并不清楚我的话。发生的情况是,每次通过循环时,x 都会被另一个值替换,所以之前发生的事情就消失了(除非你用它做了其他事情)。但是,使用您正在使用的操作,您不会更改列表中任何元素的值。我对混乱不好。
当你以另一种方式做时,
for x in range(len(lst)):
lst[x] += 1
然后你在谈论列表的值。x 是变量的索引,因此可以在该位置更改列表值的值。
这里重要的概念是引用的概念。在 Python 中,变量是对位于内存某处的对象的引用。让我们使用箭头 → 来表示引用。变量→对象。左边是变量,右边是对象。
可以将数组可视化为引用三个整数对象的三个变量。
a[0] → int(1)
a[1] → int(2)
a[2] → int(3)
现在,整数对象是不可变的。它们不能改变。当您更改整数变量时,您不会更改变量所引用的对象。你不能,因为int
s 是不可变的。您可以做的是使变量引用不同的对象。
让我们先看看第二个循环,因为它更简单。如果直接更新数组会发生什么?
for i in range(0, len(a)):
a[i] += 1
首先让我们展开循环:
a[0] += 1
a[1] += 1
a[2] += 1
对于整数,a[0] += 1
等价于a[0] = a[0] + 1
。首先,Python 评估a[0] + 1
并获得结果int(2)
。然后它更改a[0]
为 reference int(2)
。第二个和第三个语句的评估类似。
a = [1, 2, 3] # a[0] → int(1)
# a[1] → int(2)
# a[2] → int(3)
a[0] += 1 # a[0] → int(2)
a[1] += 1 # a[1] → int(3)
a[2] += 1 # a[2] → int(4)
那我称之为“间接”更新呢?
for x in a:
x += 1
展开循环会产生这一系列等效的语句:
x = a[0]
x += 1
x = a[1]
x += 1
x = a[2]
x += 1
每一步会发生什么,为什么数组没有改变?
x = a[0]
这使得x
引用任何对象a[0]
引用。两者a[0]
和都x
引用同一个int(1)
对象,但x
不直接连接到a[0]
. 它指的是所指的东西a[0]
,而不是a[0]
它本身。
x += 1
这改变了x
所指的内容。它对 没有影响a[0]
。
第二个和第三个作业也会发生同样的事情。结果是x
不断变化,而元素a
只是被读取但从未被修改。所以当循环终止时a
是不变的。
a = [1, 2, 3] # a[0] → int(1)
# a[1] → int(2)
# a[2] → int(3)
x = a[0] # x → int(1)
x += 1 # x → int(2)
x = a[1] # x → int(2)
x += 1 # x → int(3)
x = a[2] # x → int(3)
x += 1 # x → int(4)
把它想象成在你的第一个循环中,x 只是 a 中每个元素的替代品。它不是实际的元素a
(尽管id()
这是因为它们都引用了同一个对象)。当你这样做x += 1
时,你只是在改变x
列表中的值而不是值。
在您的第二个 for 循环中,您实际上是通过执行a[i] += 1
.