我创建了一个列表的列表:

>>> xs = [[1] * 4] * 3
>>> print(xs)
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

然后,我改变了最里面的一个值:

>>> xs[0][0] = 5
>>> print(xs)
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]

为什么每个子列表的第一个元素都变成了5?


参见:

我如何克隆一个列表,使它不会在分配后意外改变?寻找解决问题的方法

Python:对于字典列表的类似问题,字典列表只存储每次迭代中最后追加的值

如何初始化一个字典,其值是不同的空列表?对于列表字典的类似问题


当前回答

实际上,这正是你所期望的。让我们分解这里发生的事情:

你写

lst = [[1] * 4] * 3

这相当于:

lst1 = [1]*4
lst = [lst1]*3

这意味着lst是一个有3个元素都指向lst1的列表。这意味着下面两行是等价的:

lst[0][0] = 5
lst1[0] = 5

因为lst[0]就是lst1。

为了获得想要的行为,你可以使用列表推导式:

lst = [ [1]*4 for n in range(3) ]

在这种情况下,对每个n重新计算表达式,得到不同的列表。

其他回答

每个人都在解释发生了什么。我将提出一种解决方法:

my_list = [[1 for i in range(4)] for j in range(3)]

my_list[0][0] = 5
print(my_list)

然后你得到:

[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

通过使用内置的列表函数,您可以这样做

a
out:[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#Displaying the list

a.remove(a[0])
out:[[1, 1, 1, 1], [1, 1, 1, 1]]
# Removed the first element of the list in which you want altered number

a.append([5,1,1,1])
out:[[1, 1, 1, 1], [1, 1, 1, 1], [5, 1, 1, 1]]
# append the element in the list but the appended element as you can see is appended in last but you want that in starting

a.reverse()
out:[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#So at last reverse the whole list to get the desired list

My_list =[[1]*4] * 3在内存中创建一个列表对象[1,1,1,1],并将其引用复制3次。这相当于obj = [1,1,1,1];My_list = [obj]*3。对obj的任何修改都将反映在列表中引用obj的三个位置。 正确的说法应该是:

my_list = [[1]*4 for _ in range(3)]

or

my_list = [[1 for __ in range(4)] for _ in range(3)]

这里需要注意的重要一点是,*操作符主要用于创建文字列表。虽然1是不可变的,但obj =[1]*4仍然会创建一个重复4次的1的列表,形成[1,1,1,1]。但是,如果对不可变对象进行了引用,则该对象将被一个新的对象覆盖。

这意味着如果我们执行obj[1] = 42,那么obj将变成[1,42,1,1],而不是一些人可能认为的[42,42,42,42]。这也可以验证:

>>> my_list = [1]*4
>>> my_list
[1, 1, 1, 1]

>>> id(my_list[0])
4522139440
>>> id(my_list[1])  # Same as my_list[0]
4522139440

>>> my_list[1] = 42  # Since my_list[1] is immutable, this operation overwrites my_list[1] with a new object changing its id.
>>> my_list
[1, 42, 1, 1]

>>> id(my_list[0])
4522139440
>>> id(my_list[1])  # id changed
4522140752
>>> id(my_list[2])  # id still same as my_list[0], still referring to value `1`.
4522139440

Python容器包含对其他对象的引用。请看这个例子:

>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]

其中b是一个列表,其中包含一个对列表a的引用。列表a是可变的。

将列表与整数相乘相当于将列表与自身相加多次(请参阅常用序列操作)。继续这个例子:

>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]

我们可以看到,列表c现在包含两个对列表a的引用,这等价于c = b * 2。

Python常见问题还包含对这种行为的解释:如何创建多维列表?

当你写[x]*3时,你会得到[x, x, x]这个列表。也就是说,一个有3个对同一个x的引用的列表。当你修改这个x时,它通过所有三个对它的引用都是可见的:

x = [1] * 4
xs = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
    f"id(xs[0]): {id(xs[0])}\n"
    f"id(xs[1]): {id(xs[1])}\n"
    f"id(xs[2]): {id(xs[2])}"
)
# id(xs[0]): 140560897920048
# id(xs[1]): 140560897920048
# id(xs[2]): 140560897920048

x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"xs: {xs}")
# xs: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]

为了解决这个问题,您需要确保在每个位置都创建了一个新列表。一种方法是

[[1]*4 for _ in range(3)]

它将每次重新计算[1]*4,而不是计算一次并对1个列表进行3次引用。


You might wonder why * can't make independent objects the way the list comprehension does. That's because the multiplication operator * operates on objects, without seeing expressions. When you use * to multiply [[1] * 4] by 3, * only sees the 1-element list [[1] * 4] evaluates to, not the [[1] * 4 expression text. * has no idea how to make copies of that element, no idea how to reevaluate [[1] * 4], and no idea you even want copies, and in general, there might not even be a way to copy the element.

*的唯一选择是对现有子列表进行新的引用,而不是尝试创建新的子列表。其他任何东西都是不一致的,或者需要对基本语言设计决策进行重大的重新设计。

相比之下,列表推导式在每次迭代时重新计算元素表达式。[[1] * 4 for n in range(3)]每次重新计算[1]* 4,原因相同[x**2 for x in range(3)]每次重新计算x**2。每次对[1]* 4求值都会生成一个新列表,因此列表推导式执行您想要的操作。

顺便说一句,[1]* 4也不复制[1]的元素,但这没关系,因为整数是不可变的。你不能做类似于1的东西。Value = 2,把1变成2。