Python替换None为递增值时重复追加子列表同步修改问题排查
问题根因
Python中列表是可变对象,你在构建列表a时,多次执行a.append(i)追加的是源子列表的内存引用,不是独立的新列表对象。也就是说,重复追加的3个[1,None,3]、2个[7,None,2]本质上都是指向内存中同一个列表的别名,你修改其中任意一个的元素,所有指向该内存地址的列表都会同步变化——这就是同源子列表会一起被修改的核心原因,甚至源列表b里的对应子列表也会被你的赋值操作改动。
问题复现
原问题代码:
b = [[1,None,3],[4,5,1],[7,None,2]] a = [] for i in b: for rp in range(i[2]): a.append(i) print(b) print(a) c = 0 for i in range(len(a)): if a[i][1]==None: a[i][1] = c c = c + 1 print(a)
- 实际运行结果:
[[1, None, 3], [4, 5, 1], [7, None, 2]] [[1, None, 3], [1, None, 3], [1, None, 3], [4, 5, 1], [7, None, 2], [7, None, 2]] [[1, 0, 3], [1, 0, 3], [1, 0, 3], [4, 5, 1], [7, 1, 2], [7, 1, 2]]
- 预期运行结果:
[[1, 0, 3], [1, 1, 3], [1, 2, 3], [4, 5, 1], [7, 3, 2], [7, 4, 2]]
修复方案
追加子列表时,不要直接追加原引用,而是生成原列表的浅拷贝即可(子列表内元素都是不可变的整数、None,浅拷贝足够生成完全独立的新列表对象)。两种常用的浅拷贝写法选一种替换原来的append逻辑就行:
- 切片写法:
a.append(i[:]) - 构造函数写法:
a.append(list(i))
修复后的完整代码:
b = [[1,None,3],[4,5,1],[7,None,2]] a = [] for i in b: for rp in range(i[2]): # 追加独立的浅拷贝对象,和原列表引用解绑 a.append(i[:]) c = 0 for i in range(len(a)): # 判断None推荐使用is关键字,符合Python编码规范 if a[i][1] is None: a[i][1] = c c += 1 print(a)
运行上述代码即可得到预期输出。
补充说明:如果子列表内还嵌套了其他可变对象(比如子列表里还有列表),浅拷贝无法完全解绑,需要用
copy.deepcopy()做深拷贝,当前场景不需要。
内容的提问来源于stack exchange,提问作者npatel
相关产品推荐
相关产品推荐

