Python列表追加字典时已存入数据被意外修改问题排查
问题根因
Python列表的append()方法存储的是对象的内存引用,不是对象的独立拷贝。
你在外层遍历时间戳的循环中,每个时间戳仅初始化了1次raw字典,内层5次循环全程都在修改这同一个字典对象。每次append操作只是把这个字典的内存地址存入列表,并没有生成新的字典。
你在append之后立刻打印data[-1]时值正常,是因为刚完成tag赋值,此时字典的tag值就是当前count;等下一次内层循环修改同一个raw的tag字段时,列表里之前存的所有指向该内存地址的条目,都会同步显示修改后的最新值,最终同时间戳的5条记录tag会全部等于该批次最后一次赋值的结果。
对应典型错误实现
import pandas as pd from random import randrange, choice # 菌种基础数据 cultures = [ {"culture_name": "大肠杆菌", "scientific_name": "Escherichia coli"}, {"culture_name": "枯草芽孢杆菌", "scientific_name": "Bacillus subtilis"}, {"culture_name": "金黄色葡萄球菌", "scientific_name": "Staphylococcus aureus"} ] times = pd.date_range(start="2024-01-01", periods=10, freq="D") data = [] count = 0 for ts in times: # 问题点:每个时间戳只创建1个字典,内层循环全程复用 raw = dict() selected_culture = choice(cultures) raw["culture_name"] = selected_culture["culture_name"] raw["scientific_name"] = selected_culture["scientific_name"] raw["generation"] = randrange(1, 30) raw["stage"] = randrange(1, 6) raw["user_id"] = 1 raw["created_at"] = ts raw["updated_at"] = ts for _ in range(5): raw["tag"] = count count += 1 data.append(raw) # 此时打印刚修改完的字典,值看似正确 print("刚追加的条目:", data[-1])
修复方案
核心原则:每次append到列表的必须是独立的字典对象,不要跨循环复用同一个可变字典。
针对你的场景,最简便的写法是把固定字段先存为基础字典,内层循环每次生成基础字典的浅拷贝,再赋值独立的tag字段:
for ts in times: selected_culture = choice(cultures) # 先组装同时间戳下共有的固定字段 base_data = { "culture_name": selected_culture["culture_name"], "scientific_name": selected_culture["scientific_name"], "generation": randrange(1, 30), "stage": randrange(1, 6), "user_id": 1, "created_at": ts, "updated_at": ts } for _ in range(5): # 每次循环生成独立副本,再赋值独有的tag字段 raw = base_data.copy() raw["tag"] = count count += 1 data.append(raw)
如果后续字典里存在嵌套的可变对象(比如值是列表、其他字典),把base_data.copy()换成copy.deepcopy(base_data)即可,当前场景全是一维不可变值,浅拷贝完全够用。
修复后再打印全量data列表,50条数据的tag会从0到49连续递增,不会再出现同批次tag重复的问题。
内容的提问来源于stack exchange,提问作者The Candy King
相关产品推荐
相关产品推荐

