Python中用*运算符创建二维数组更新时出现意外副作用的原因
为什么Python中用
[ [0]*5 ]*8创建二维数组会导致所有行同步更新? 先看你给出的代码和运行结果:
dp1 = [ [0] * 5 ] * 8 dp1[2][2] = dp1[1][1] + 1 print("DP1") for dp in dp1: print(dp) dp2 = [[0] * 5 for _ in range(8)] dp2[2][2] = dp2[1][1] + 1 print("DP2") for dp in dp2: print(dp)
输出:
DP1 [0, 0, 1, 0, 0] [0, 0, 1, 0, 0] [0, 0, 1, 0, 0] [0, 0, 1, 0, 0] [0, 0, 1, 0, 0] [0, 0, 1, 0, 0] [0, 0, 1, 0, 0] [0, 0, 1, 0, 0] DP2 [0, 0, 0, 0, 0] [0, 0, 0, 0, 0] [0, 0, 1, 0, 0] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0] [0, 0, 0, 0, 0]
核心原因:列表的引用复用
Python里的列表是可变对象,当你用[ [0]*5 ]*8时,本质是先创建了一个子列表[0,0,0,0,0],然后把这个子列表的引用重复了8次放到外层列表里。也就是说,dp1里的8个元素,全都是指向同一个内存地址的子列表。
你可以用id()函数验证这一点:
dp1 = [ [0]*5 ]*8 print(id(dp1[0]), id(dp1[1]), id(dp1[2])) # 输出三个完全相同的内存地址
所以当你修改dp1[2][2]时,其实是在修改那个唯一的子列表,自然所有行都会显示出这个修改。
而方法2用的[[0]*5 for _ in range(8)],是通过列表推导式循环8次,每次循环都会新建一个[0]*5的子列表。每个子列表都是独立的对象,内存地址各不相同,修改其中一行只会影响该行本身。
总结
要创建行独立的二维数组,必须确保每一行都是新的列表实例,推荐用列表推导式的方式(方法2),或者手动循环创建每行。
内容的提问来源于stack exchange,提问作者Dracula
相关产品推荐
相关产品推荐

