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

>>> 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:对于字典列表的类似问题,字典列表只存储每次迭代中最后追加的值

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


当前回答

为了更详细地解释它,

操作1:

x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]

x[0][0] = 1
print(x) # [[1, 0], [0, 0]]

操作2:

y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [1, 0]]

注意到为什么修改第一个列表的第一个元素不修改每个列表的第二个元素吗?这是因为[0]* 2实际上是两个数字的列表,对0的引用不能被修改。

如果您想创建克隆副本,请尝试操作3:

import copy
y = [0] * 2   
print(y)   # [0, 0]

y = [y, copy.deepcopy(y)]  
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [0, 0]]

另一种创建克隆副本的有趣方法,操作4:

import copy
y = [0] * 2
print(y) # [0, 0]

y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]

y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]

其他回答

为了更详细地解释它,

操作1:

x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]

x[0][0] = 1
print(x) # [[1, 0], [0, 0]]

操作2:

y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [1, 0]]

注意到为什么修改第一个列表的第一个元素不修改每个列表的第二个元素吗?这是因为[0]* 2实际上是两个数字的列表,对0的引用不能被修改。

如果您想创建克隆副本,请尝试操作3:

import copy
y = [0] * 2   
print(y)   # [0, 0]

y = [y, copy.deepcopy(y)]  
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [0, 0]]

另一种创建克隆副本的有趣方法,操作4:

import copy
y = [0] * 2
print(y) # [0, 0]

y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]

y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]

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

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程序员;考虑:

>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]

[[]]是一个包含空列表的单元素列表,因此[[]]* 3的所有三个元素都是对这个空列表的引用。修改列表中的任何元素都会修改这个列表。

另一个解释这一点的例子是使用多维数组。

你可能尝试过这样做一个多维数组:

>>> A = [[None] * 2] * 3

如果你打印出来,看起来是正确的:

>>> A
[[None, None], [None, None], [None, None]]

但当你赋值时,它会出现在多个地方:

>>> A[0][0] = 5
>>> A
[[5, None], [5, None], [5, None]]

原因是使用*复制列表不会创建副本,它只创建对现有对象的引用。3创建一个包含3个对长度为2的相同列表的引用的列表。对一行的更改将显示在所有行中,这几乎肯定不是您想要的。

size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for _ in range(size)]

使用Python导师进行实时可视化: