Python列表乘法:[[...]]*3会生成3个列表,当修改其中一个列表时,其他两个也会同步修改。

46

为什么会发生这种情况?我真的不太明白:

>>> P = [ [()]*3 ]*3
>>> P
[[(), (), ()], [(), (), ()], [(), (), ()]]
>>> P[0][0]=1
>>> P
[[1, (), ()], [1, (), ()], [1, (), ()]]

3
为什么只有外部的 *3 会创建更多的引用,而内部的不会?为什么不全部都是 1 - spelchekr
@spelchekr 因为当你赋值时,一个新的对象将被创建。参考: https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/ - cges30901
4个回答

37

您已经对同一个列表进行了3次引用。

>>> a = b = []
>>> a.append(42)
>>> b
[42]
你想要做这个:
P = [[()] * 3 for x in range(3)]

8

列表是可变的,将列表乘以一个数字并不会复制其元素。您可以尝试将其更改为列表推导式,这样它将评估[()]*3三次,创建三个不同的列表:

P = [ [()]*3 for i in range(3) ]

这个答案需要更多的关注 - “列表是可变的,将列表乘以一个数字并不会复制它的元素。” - CyberPlayerOne

6

实际上,这是同一个内部列表(相同的引用)被复制了3次,因此当您修改其中任何一个时,实际上都在修改所有列表。

因此,内部列表[()]*3生成三个元组的列表。但是在Python中,实际上是正在乘以引用的列表,因此引用被复制,但每个引用仍然指向相同的基础列表。


5

你还可以这样写,这种方式的优点是显示了结构:[[()]*3]*3

>>> P=[i[:] for i in [[()]*3]*3]
>>> P[0][0]=1
>>> P
[[1, (), ()], [(), (), ()], [(), (), ()]

相比使用range,它稍微快一些。来自ipython shell:

In [1]: timeit P = [ [()]*3 for i in range(3) ]
1000000 loops, best of 3: 1.41 us per loop

In [2]: timeit P=[i[:] for i in [[()]*3]*3]
1000000 loops, best of 3: 1.27 us per loop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接