(又一个)列表别名困境

5 投票
6 回答
5248 浏览
提问于 2025-04-17 11:02

我以为我已经搞懂了列表别名的事情,但后来我遇到了这个:

    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 = 0i[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 中的名字只是对象的标签。作用域或命名空间就像一个字典,把名字映射到对象上。

撰写回答