如果我有以下列表:
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
?
答案 0 :(得分:5)
当您遍历列表时,依次会产生每个元素。但是,有不同种类的对象。 mutable 和 immutable 。当你做类似的事情时:
a += 1
使用不可变对象,它大致翻译为:
a = a + 1
现在,在这种情况下,您可以通过a
获取对象引用,为其添加1以创建新对象。然后,为该新对象分配名称a
。请注意,如果我们在迭代时执行此操作,我们根本不会触及列表 - 我们只会继续创建新对象并将它们分配给名称a
。
对于可变对象,这是不同的。然后a += 1
实际上将对象更改为。因此,列表将看到更改,因为它所持有的对象已更改(已更改)。 (对于不可变对象,列表中包含的对象未被更改,因为它不可能)。有关详细信息,请参阅this question。
当你按索引进行迭代时,这也会让你更清楚一下发生了什么。你构造一个新的整数,然后把它放在列表中(忘记之前那个插槽中的内容)。
答案 1 :(得分:3)
当你说,
for x in [1,2,3]:
x+=1
您说,暂时将x保存为变量,并为该临时保存添加一个。当你进入下一次迭代时,垃圾人会破坏该变量,因为它是暂时的。 x不是列表中的位置。它是列表中该点的值。
编辑:当我说它被删除时,我不清楚我的话。会发生的是每次循环时,x都被另一个值替换,所以之前发生的事情就会消失(除非你用它做了其他的事情)。但是,对于您正在使用的操作,您不会更改列表中任何元素的值。我不好意思混乱。
当你以其他方式这样做时,
for x in range(len(lst)):
lst[x] += 1
然后你在谈论列表的价值观。 x是变量的索引,因此可以改变该位置列表值的值。
答案 2 :(得分:2)
这里重要的概念是引用的想法。在Python中,变量是对位于内存中的对象的引用。我们使用箭头→表示参考。变量→对象。左边是变量,右边是对象。
可以将数组可视化为引用三个整数对象的三个变量。
a[0] → int(1)
a[1] → int(2)
a[2] → int(3)
现在,整数对象是不可变的。它们无法改变。当您更改整数变量时,您不会更改变量引用的对象。你不能,因为int
是不可变的。你可以做的是使变量引用成为一个不同的对象。
让我们先看看第二个循环,因为它更简单。如果直接更新阵列会发生什么?
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]
更改为引用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)
答案 3 :(得分:1)
将其视为第一个循环,x只是替代a中的每个元素。它不是a
中的实际元素(尽管id()
是因为它们都引用了同一个对象)。当您执行x += 1
时,您只是更改了x
的值,而不是列表中的值。
在您的第二个for循环中,您通过执行a[i] += 1
实际修改了列表。