Python创建二维列表的正确姿势
Python创建二维列表的正确姿势
简介
Python中没有数组,使用list
结构代替,并且list
结构的功能更加强大:
- 支持动态扩容,无需担心元素过量
- 对list内的元素类型不做一致性约束
- 提供丰富的方法:pop、insert、sort、index等等
- ...
list
也是我们最常使用的一种结构,我们也需要了解它的一些特性,学会正确使用它。
探索列表的初始化
初始化一维列表
>>> month = ["January", "February", "March"]
初始化二维列表
>>> row, col = 3, 4
>>> right_matrix = [[0] * col for _ in range(row)]
>>> wrong_matrix = [[0] * col] * row
>>> print(right_matrix)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> print(wrong_matrix)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
看似两种方式初始化出的二维列表是一样的,但为啥第二种是wrong_matrix
呢?它会有问题呢?
如果我们尝试更新试试
>>> right_matrix[0][0] = 1
>>> print(right_matrix)
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] # 正常
>>> wrong_matrix[0][0] = 1
>>> print(wrong_matrix)
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]] # 不正常,每行第一列都被更新成了1
分析两种初始化方式的内存情况
率先想到的是list
属于可变数据结,在函数传递过程中容易发生浅拷贝
(在函数内部的更改不会影响函数外部该变量的值)。
>>> id(right_matrix[0]), id(right_matrix[1]), id(right_matrix[2])
(288926611776, 288926609600, 288926609472)
>>> id(wrong_matrix[0]), id(wrong_matrix[1]), id(wrong_matrix[2])
(288926610176, 288926610176, 288926610176)
使用id()
函数可以获取对象的内存id,发现right_martix
中每行的id是不同的,它们都是独立的list对象,而wrong_matrix
中每行的id是相同的,它们是同一个lsit对象,所以会出现上面的情况:目的是改wrong_matrix[0][0]
,但实际上wrong_matrix[1][0]
和wrong_martix[2][0]
也被修改了。
使用http://pythontutor.com/visualize.html#mode=edit 网站执行上面的right_matrix
和wrong_matrix
代码来对比实际的内存情况,来验证一下
right_matrix
:
wrong_matrix
:
right_matrix
中每个list对象都有独立的内存空间,而wrong_matrix
中每个list对象指向同一块内存空间。
结论
list的元素如果是可变数据类型,一定要用方法一的方式初始化
>>> row, col = 3, 4
>>> right_matrix = [[0] * col for _ in range(row)]
这种方式下,right_matrix
里的每个list对象都有独立的内存空间,不会出现修right_matrix[0][0]
,right_matrix[1][0]
和right_martix[2][0]
也被修改的情况。