为嵌套字典分配随机列表时所有项均被赋值为最后生成的列表
Why does all keys in my parent dictionary reference the last sub-dictionary?
哦,这个坑我太熟了!你遇到的是Python里可变对象引用赋值的经典问题——每次把temp字典赋值给d[x]时,你并没有复制temp的内容,而是把temp这个字典对象的内存引用存到了d里。也就是说,d[0]、d[1]、d[2]其实都指向同一个字典实例,最后循环结束时,这个实例里的内容是最后一次循环修改的结果,所以所有键对应的都是最后那组随机列表。
你的问题代码
import numpy as np # 补充你原代码遗漏的numpy导入 temp = {} d = {} for x in range(3): for i in range(3): temp[i] = list(np.random.randint(10, size=10)) print(x) print(temp) d[x] = temp print(d[x]) print("--------------------------") print("The final dictionary: ", d)
运行输出
0 {0: [1, 4, 1, 7, 3, 9, 3, 8, 1, 5], 1: [6, 5, 2, 0, 5, 0, 5, 9, 7, 1], 2: [7, 9, 3, 3, 5, 8, 6, 0, 6, 0]} {0: [1, 4, 1, 7, 3, 9, 3, 8, 1, 5], 1: [6, 5, 2, 0, 5, 0, 5, 9, 7, 1], 2: [7, 9, 3, 3, 5, 8, 6, 0, 6, 0]} -------------------------- 1 {0: [0, 0, 7, 0, 0, 1, 9, 9, 2, 0], 1: [1, 5, 8, 7, 2, 9, 0, 8, 7, 9], 2: [8, 8, 4, 8, 1, 1, 1, 2, 4, 4]} {0: [0, 0, 7, 0, 0, 1, 9, 9, 2, 0], 1: [1, 5, 8, 7, 2, 9, 0, 8, 7, 9], 2: [8, 8, 4, 8, 1, 1, 1, 2, 4, 4]} -------------------------- 2 {0: [5, 4, 7, 1, 1, 3, 0, 3, 6, 9], 1: [5, 9, 7, 8, 0, 7, 1, 7, 6, 9], 2: [4, 2, 6, 1, 3, 7, 2, 6, 4, 8]} {0: [5, 4, 7, 1, 1, 3, 0, 3, 6, 9], 1: [5, 9, 7, 8, 0, 7, 1, 7, 6, 9], 2: [4, 2, 6, 1, 3, 7, 2, 6, 4, 8]} -------------------------- The final dictionary: {0: {0: [5, 4, 7, 1, 1, 3, 0, 3, 6, 9], 1: [5, 9, 7, 8, 0, 7, 1, 7, 6, 9], 2: [4, 2, 6, 1, 3, 7, 2, 6, 4, 8]}, 1: {0: [5, 4, 7, 1, 1, 3, 0, 3, 6, 9], 1: [5, 9, 7, 8, 0, 7, 1, 7, 6, 9], 2: [4, 2, 6, 1, 3, 7, 2, 6, 4, 8]}, 2: {0: [5, 4, 7, 1, 1, 3, 0, 3, 6, 9], 1: [5, 9, 7, 8, 0, 7, 1, 7, 6, 9], 2: [4, 2, 6, 1, 3, 7, 2, 6, 4, 8]}}
问题根源
在Python中,字典是可变对象。当你执行d[x] = temp时,不是把temp的内容复制一份存到d[x],而是把temp这个对象的内存地址存了进去。所以d里的所有键都指向同一个temp字典,每次循环修改temp的内容,其实是在修改同一个对象,最后所有引用都会看到最后一次修改的结果。
解决方案
方法1:每次循环创建新的temp字典
把temp = {}放到外层循环内部,这样每次循环都会生成一个全新的字典对象,彻底避免引用冲突:
import numpy as np d = {} for x in range(3): temp = {} # 每次循环新建独立字典 for i in range(3): temp[i] = list(np.random.randint(10, size=10)) print(x) print(temp) d[x] = temp print(d[x]) print("--------------------------") print("The final dictionary: ", d)
方法2:复制temp字典再赋值
如果不想移动temp的定义,可以用字典的copy()方法(或dict(temp))创建副本,这样d[x]存的是副本的引用,和原temp无关:
import numpy as np temp = {} d = {} for x in range(3): for i in range(3): temp[i] = list(np.random.randint(10, size=10)) print(x) print(temp) d[x] = temp.copy() # 复制字典副本 # 等价写法:d[x] = dict(temp) print(d[x]) print("--------------------------") print("The final dictionary: ", d)
两种方法都能解决问题,第一种更直观,适合大多数场景;第二种适合需要保留原temp对象的特殊情况。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

