为何两段二维数组元素更新的Python代码输出结果存在差异
两段二维列表初始化代码的输出差异原理
核心差异来源:Python 的可变对象引用规则
两种写法的根本区别是,外层大列表存储的是“共享的同一个子列表引用”还是“互相独立的多个子列表引用”,拆解执行逻辑如下:
代码1的实际执行逻辑
- 第一步执行
[0] * d时,因为0是不可变整数,这里会生成1个独立的、全新的长度为5的一维列表对象,占用独立内存空间。 - 第二步执行
[...] * d时,*运算符的作用是将当前已生成的那个一维列表的内存引用,重复、原样地复制到外层大列表的5个索引位置,不会新生成任何子列表对象。
简单说:外层的matrix_list[0]、matrix_list[1]……matrix_list[4],存的全是同一个内存地址的指针,本质指向的是同一块列表内存。 - 当执行
matrix_list[0][3] = 1时,程序顺着matrix_list[0]存的指针,找到唯一的那块子列表内存,把第3个元素修改为1。因为所有外层索引指向的都是这块内存,遍历打印时拿到的自然全是被修改过的同一个列表,最终输出5行都带1的结果。踩这个坑的核心认知误区:很多开发者误以为
*运算符重复可变对象时会自动创建新副本,实际上Python的*操作对可变对象只会复制引用,不会做深拷贝。
代码2的实际执行逻辑
- 手动逐行书写的5个
[0,0,0,0,0],在Python语法解析阶段,会为每一个方括号块生成拥有全新内存地址的独立一维列表对象。 - 外层
matrix_list的5个索引,分别存了5个完全不同的子列表的引用,对象之间没有任何内存关联。 - 当执行
matrix_list[0][3] = 1时,只会修改第一个引用对应的独立子列表,剩下4个子列表完全不受影响,因此输出只有第一行带1。
补充正确的二维列表初始化方式
如果要通过简写生成互不干扰的二维列表,不要直接用外层*的写法,应使用列表推导式:matrix_list = [[0] * d for _ in range(d)]
这种写法每轮循环都会新生成一个独立的子列表,不存在共享引用的问题。
内容的提问来源于stack exchange,提问作者Kim
相关产品推荐
相关产品推荐

