Python二维列表实测:列表乘法和浅复制为何共享内层对象

举报
yd_214130845 发表于 2026/10/29 12:14:39 2026/10/29
【摘要】 六组Python实测,解释二维列表乘法、外层浅复制和deepcopy对共享引用的不同处理,给出独立行初始化与复制方法。

改一个位置,为什么三行都变了

用列表存表格、棋盘或批量任务状态时,[[0] * 2] * 3 看起来像“三行两列”。但它创建的是三个指向同一个行列表的引用。下面六组代码已在 Python 3.10.4 中实际运行,并用断言核对结果。

bad = [[0] * 2] * 3
bad[0][0] = 9
print(bad)
# [[9, 0], [9, 0], [9, 0]]
print(bad[0] is bad[1])
# True

问题不在索引:赋值只修改了一个行对象,只是三处都引用它。外层乘法重复的是引用,不会为每一行重新执行一次内部列表的构造。判断是否为同一对象要用 is,不能仅凭两个列表的值相等来判断。

1. 构造时让每行分别创建

good = [[0] * 2 for _ in range(3)]
good[0][0] = 9
print(good)
# [[9, 0], [0, 0], [0, 0]]
print(good[0] is good[1])
# False

列表推导式会在每轮创建新的行列表。这里的单元格是不可变整数,因此可以使用 [0] * 2 初始化一行。如果把单元格换成可变字典或列表,还需要继续检查单元格是否共享,不能把“行已独立”理解为任意层级都独立。

2. 外层copy不会复制每一行

original = [[1, 2], [3, 4]]
copied = original.copy()
copied[0][0] = 8
print(original)
# [[8, 2], [3, 4]]
print(copied is original, copied[0] is original[0])
# False True

copy() 返回新的外层列表,但保留原来的行对象引用。用切片 original[:] 同样是浅复制。只比较外层的身份,容易误以为已经获得完全独立的数据。

对于本例这种只有两层、单元格为整数的结构,可以逐行复制:

original = [[1, 2], [3, 4]]
copied = [row.copy() for row in original]
copied[0][0] = 8
print(original, copied)
# [[1, 2], [3, 4]] [[8, 2], [3, 4]]

这解决了行对象共享;如果行中还嵌套可变对象,逐行浅复制仍然不够,需要根据数据结构决定复制深度。

3. deepcopy也不会自动纠正原有共享关系

from copy import deepcopy

shared = [[0] * 2] * 3
copied = deepcopy(shared)
copied[0][0] = 7
print(shared)
# [[0, 0], [0, 0], [0, 0]]
print(copied)
# [[7, 0], [7, 0], [7, 0]]

这次修改不会影响原对象,但副本中的三行仍指向同一个新行对象。对这个由列表和整数组成的结构,deepcopy 会在一次复制过程中记录已经复制的对象,遇到同一行时复用其副本。因此,“与原对象分离”和“副本内部每行独立”是两个不同要求。

如果确认业务上每行应当独立,可以在本例中分别复制每行:

copied = [deepcopy(row) for row in shared]
copied[0][0] = 7
print(copied)
# [[7, 0], [0, 0], [0, 0]]

每次调用分别建立复制记录,所以这些行会分开。但有些结构本来就需要共享对象,不能不加区分地拆开所有引用。更直接的做法通常是在初始化阶段创建独立行,避免后续修补。

实际排查顺序

先打印修改前后的值,再检查外层、行和可变单元格的身份。初始化表格时逐行创建;复制已有数据时明确需要隔离到哪一层;如果使用 deepcopy,还要确认原数据内部的共享关系是否符合业务设计。六组示例验证的是这些具体结构的行为,不代表所有自定义对象都会按相同方式复制。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。