(又一个)列表别名困境
我以为我已经搞懂了列表别名的事情,但后来我遇到了这个:
l = [1, 2, 3, 4]
for i in l:
i = 0
print(l)
结果是:
[1, 2, 3, 4]
到目前为止一切正常。
但是,当我尝试这个:
l = [[1, 2], [3, 4], [5, 6]]
for i in l:
i[0] = 0
我得到了
[[0, 2], [0, 4], [0, 5]]
这是为什么呢?
这和别名的深度有关吗?
6 个回答
2
for i in l:
这句话的意思是“每次循环的时候,i
将代表列表l
中的下一个元素”。
i = 0
这句话的意思是“i
将不再代表它当前所代表的东西,而是开始代表整数对象0
”。
i[0] = 0
这句话的意思是“i
所代表的东西的第一个元素将被0
替换”。(你不能说“i[0]
将不再代表...”因为它并不是一个名字。)
9
第一个重新绑定了名字。重新绑定名字只会改变本地的名字。第二个改变了对象。改变对象会让它在所有地方都发生变化(因为它始终是同一个对象)。
6
i = 0
和 i[0] = 0
是完全不同的事情。
Ignacio 已经简明扼要地解释了原因。接下来我会用更简单的语言来说明这里到底发生了什么。
在第一个例子中,i
只是一个指向某个对象的标签(这个对象是你列表中的一个成员)。当你写 i = 0
时,你实际上是把这个标签指向了另一个对象,所以现在 i
指向的是数字 0
。列表本身没有被改变,因为你并没有要求修改 l[0]
或者列表 l
中的任何元素,你只是修改了 i
。
在第二个例子中,i
仍然是指向列表中某个成员的名字,这部分没有变化。不过,i[0]
现在是在调用这个列表成员的 .__getitem__(0)
方法。类似地,i[0] = 'other'
就像是在做 i.__setitem__(0, 'other')
。这并不是简单地把 i
指向一个不同的对象,像普通的赋值语句那样,而是实际上在改变对象 i
的内容。
一个简单的理解方式是,Python 中的名字只是对象的标签。作用域或命名空间就像一个字典,把名字映射到对象上。