如何对从pickle文件读取的同结构字典逐键求和?
我一眼就看出问题所在啦——你的代码里用update方法直接复制字典时,做的是浅拷贝,也就是说accumulated_damage里的内层字典其实是和old_damage、current_damage里的内层字典共享同一个内存引用的。尤其是当你测试用同一个字典自身求和时,第一次修改accumulated_damage[i][j]的时候,其实也偷偷修改了current_damage里对应的值,等到循环到下一个外层键时,你加的就不是原始的1.00E+00,而是已经被修改过的2.00E+00,自然就得出了3.00E+00的错误结果。
那怎么解决呢?我们需要创建一个完全独立的新字典,而不是直接引用原字典的内层对象。这里给你两种靠谱的写法:
方法一:逐层级创建新字典
这种方法最直观,手动遍历每一层键,创建新的内层字典来存储求和结果:
import pickle # 先读取两个字典(假设你已经完成unpickle步骤) with open('old_damage.pkl', 'rb') as f: old_damage = pickle.load(f) with open('current_damage.pkl', 'rb') as f: current_damage = pickle.load(f) accumulated_damage = {} # 遍历外层键 for outer_key in old_damage.keys(): # 为每个外层键创建一个新的内层字典 accumulated_damage[outer_key] = {} # 遍历内层键 for inner_key in old_damage[outer_key].keys(): # 确保两个字典都有该键(你的try-except可以保留,防止结构不一致) try: old_val = float(old_damage[outer_key][inner_key]) current_val = float(current_damage[outer_key][inner_key]) # 求和后转成你需要的科学计数法格式 summed_val = f"{old_val + current_val:.2E}" accumulated_damage[outer_key][inner_key] = summed_val except KeyError: # 如果某一方没有这个键,可以选择保留原有的值或者跳过 if outer_key in current_damage and inner_key in current_damage[outer_key]: accumulated_damage[outer_key][inner_key] = current_damage[outer_key][inner_key] else: accumulated_damage[outer_key][inner_key] = old_damage[outer_key][inner_key]
方法二:用字典推导式简化代码
如果你的两个字典结构完全一致(题目里说结构相同),可以用嵌套的字典推导式来更简洁地实现:
accumulated_damage = { outer_key: { inner_key: f"{float(old_damage[outer_key][inner_key]) + float(current_damage[outer_key][inner_key]):.2E}" for inner_key in old_damage[outer_key] } for outer_key in old_damage }
这种写法前提是两个字典的外层键和内层键完全对应,不需要处理KeyError。如果有结构不一致的可能,还是加上try-except更稳妥。
为什么你的原代码会出问题?
再回头看你的代码:
accumulated_damage = {} accumulated_damage.update(old_damage) # 这里accumulated_damage的内层字典是old_damage的引用 accumulated_damage.update(current_damage) # 相同外层键的内层字典被替换成current_damage的引用 for i in old_damage.keys(): for j in old_damage[i].keys(): try: addition = float(current_damage[i][j])+float(old_damage[i][j]) accumulated_damage[i][j]=addition # 这里修改的是current_damage的内层字典(如果update后引用的是它) except KeyError: continue
当你用自身求和时,old_damage和current_damage是同一个对象,第一次循环修改accumulated_damage['1000']['13']时,其实也修改了current_damage['1000']['13']的值为2.0。等到循环到['1001']时,float(current_damage[i][j])已经是2.0了,加1.0就得到3.0。
所以核心就是要避免共享内层字典的引用,必须创建新的字典对象来存储结果。
内容的提问来源于stack exchange,提问作者nat

