Python中为何使用*运算符无法正确初始化多维数组?
这问题太经典了,刚学Python的时候我也栽过!先给你把原理讲明白:
先搞懂一维数组为啥没问题
你写的onedimarray = [None] * SIZE,其实是创建了一个包含SIZE个None元素的列表。因为None是不可变对象,当你后续给onedimarray[i]赋值时,是直接替换了这个位置的元素,不会影响其他位置的内容,所以一维数组能正常工作。
多维数组的坑在哪里?
问题出在multdimarray = [[None]*SIZE]*SIZE这行代码上!它的本质不是创建了SIZE个独立的子列表,而是创建了一个列表,里面的每个元素都是同一个子列表的引用。
举个直观的例子:你可以在代码里加几行打印内存地址的代码:
SIZE=3 multdimarray=[[None]*SIZE]*SIZE print(id(multdimarray[0])) print(id(multdimarray[1])) print(id(multdimarray[2]))
运行后你会发现这三个地址完全一样——也就是说,multdimarray[0]、multdimarray[1]、multdimarray[2]其实是同一个列表在内存里的不同“别名”而已。
所以当你用嵌套循环赋值时,不管你循环到i=0、i=1还是i=2,你都是在修改同一个子列表的内容。最后当i=2的循环结束后,这个子列表里的内容已经被覆盖成了最后一轮的结果,所以打印出来所有行都一模一样。
正确的多维数组初始化方式
要解决这个问题,核心是让每个子列表都是独立创建的对象,而不是复用同一个引用。给你两种常用的写法:
写法1:用嵌套循环手动创建
SIZE=3 multdimarray = [] for i in range(SIZE): # 每次循环都新建一个子列表,再添加到外层列表 row = [None] * SIZE multdimarray.append(row)
写法2:用列表推导式(更简洁)
这是Python里最常用的写法,一行搞定:
SIZE=3 multdimarray = [[None]*SIZE for _ in range(SIZE)]
这里的for _ in range(SIZE)会循环SIZE次,每次都会生成一个全新的[None]*SIZE子列表,所以每个子列表都是独立的,互相不会影响。
修正你的代码后的效果
把你的代码改成正确的初始化方式后:
SIZE=3 onedimarray=[None]*SIZE for i in range(0,SIZE): onedimarray[i]="{0:d}".format(i) print(onedimarray) # 修正后的多维数组初始化 multdimarray=[[None]*SIZE for _ in range(SIZE)] for i in range(0,SIZE): for j in range(0,SIZE): multdimarray[i][j]="{0:d},{1:d}".format(i,j) print(multdimarray)
运行后就能得到你预期的输出:
['0', '1', '2'] [['0,0', '0,1', '0,2'], ['1,0', '1,1', '1,2'], ['2,0', '2,1', '2,2']]
最后总结一下
Python里的列表是可变对象,当你用*运算符复制可变对象时,复制的是对象的引用,而不是创建新的对象。所以处理多维数组时,一定要确保每个子列表都是单独创建的,别用*来嵌套复制!
内容的提问来源于stack exchange,提问作者sbtpr

