早先在刷Leetcode的时候,遇到了一个莫名的bug
,为什么二维数组的元素没有按自己的预期改变呢?
当我们这样定义一个二维数组的时候,
n = 3
res = [[0] * n] * n
发生了什么?
[0] * n
创建了一个有n个0的list
。
[[0] * n] * n
创建了一个包含n个同一个list
的reference
。
Explanation
我们利用python
的id
方法查看对象在内存中的地址。
1D Array
初始化一个指定大小的list
很简单:
>>> zeros = [0] * 3
>>> zeros
[0, 0, 0]
>>> id(zeros)
4602255816
>>> id(zeros[0])
4559308816
>>> id(0)
4559308816
可以看到这里创建一维数组zeros
的时候,内部复制了3次0,所以其本身具有一个内存地址,元素的地址则和0
的地址相同,和我们预期的一样。
2D Array (Wrong)
利用[[0]*n]*n
创建一个二维数组。
>>> zeros2d = [[0]*3]*3
>>> zeros2d
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> zeros2d[0][1] = 1
[[0, 1, 0], [0, 1, 0], [0, 1, 0]]
这??? 只改变一个元素的值,为什么变了三个,还是相同位置的?
我们看一下它们的地址。
>>> id(zeros2d)
4602725512
>>> print([id(ele) for ele in zeros2d])
[4600869448, 4600869448, 4600869448]
内部的三个一维数组其实是一个。
警告:
这里Python对外部的list
用了相同的内部list
的引用,即本文开篇提到的。
其实从元素的地址看来创建一维和二维都一样,都是复制内部对象的引用。
2D Array (right)
知道了问题所在,那么正确的使用方式应该有如下形式:
zeros2d = [[0] * 3 for _ in range(3)]