You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Python列表推导式与列表乘法的行为表现存在差异?

n维单位矩阵初始化Bug原因

两种写法的核心差异来自Python中列表乘法的引用复制逻辑:

  • 正常运行的嵌套列表推导式写法[[0 for j in range(n)] for i in range(n)],会在外层循环的每一轮都生成一个全新的独立全0列表作为矩阵行,最终得到的n行是内存中完全独立的n个对象,修改某一行的元素不会对其他行产生影响。
  • 出问题的简化写法[[0]*n]*n,仅会在第一步生成1个全0的内层列表,外层的*n操作不会复制创建新列表,只会把这同一个内层列表的内存引用复制n次存到外层列表里。也就是说最后得到的“二维矩阵”里,所有行指向的都是同一个列表对象。

这里补充个小知识点:[0]*n本身是安全的,因为整数是不可变类型,不存在修改元素时联动影响其他位置的问题,问题只出在对可变类型(列表)做乘法复制引用的环节。

当你执行循环for i in range(n): zeros[i][i] = 1时,每一次修改本质都是操作那唯一一个被所有行共享的列表:i=0时把列表第0位改成1,i=1时把第1位改成1……循环结束后这个共享列表的所有位置都被改成了1,打印出来自然每一行都是全1的结果。

你可以通过打印对象内存id的方式直观验证这个差异:

n = 3
# 错误初始化方式
bad = [[0]*n]*n
print([id(row) for row in bad])  # 输出的n个id完全相同,证明是同一个对象

# 正确初始化方式
good = [[0]*n for _ in range(n)]
print([id(row) for row in good]) # 输出的n个id各不相同,是独立对象

如果要写更简洁的正确实现,不需要在内层用列表推导生成全0行,只要保证外层每次迭代都生成新的行列表即可,简化版正确代码如下:

def identity(n):
    mat = [[0]*n for _ in range(n)]
    for i in range(n):
        mat[i][i] = 1
    return mat

for i in range(5):
    print(identity(5)[i])

内容的提问来源于stack exchange,提问作者KevinQ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:01:29