我有一些代码,我制作了一个字典,每个值都是列表
[0,0]
。我发现增加任何列表索引都会增加每个值的相应索引;即 d[key][0] += 1
会增加彼此列表的 0 索引。
我认为 Python 对列表的浅复制是罪魁祸首,因为我的字典是使用
dict.fromkeys(keys, [0,0])
构建的。但是,在列表中使用 copy.deepcopy
时,我遇到了同样的问题。
然后我尝试了字典理解:{key:[0,0] for key in keys}
。这正如我所期望的那样;修改一个列表不会影响其他列表。
既然我找到了这个问题的解决方案,我的实际问题是为什么是这种情况。看来我要么误解了
deepcopy
的工作原理,要么与当前的问题无关,但我不知道还有什么会导致这种情况。
这是重现该行为的完整片段:
import copy
keys = [i for i in range(5)]
l = [0,0]
d = dict.fromkeys(keys, copy.deepcopy(l))
#d = {key:[0,0] for key in keys} # this approach works as expected
d[0][0] += 1
print(d)
# expected: {0: [1, 0], 1: [0, 0], 2: [0, 0], 3: [0, 0], 4: [0, 0]}
# actual: {0: [1, 0], 1: [1, 0], 2: [1, 0], 3: [1, 0], 4: [1, 0]}
您只制作列表的一份副本,并将其用于字典中的每个值。函数参数仅计算一次,结果将传递给函数。所以当你写的时候
d = dict.fromkeys(keys, copy.deepcopy(l))
它实际上相当于
temp = copy.deepcopy(l)
d = dict.fromkeys(keys, temp)
改用字典理解,这样您就可以为每个元素创建一个新副本。
d = {key: copy.deepcopy(l) for key in keys}
在这种情况下,
deepcopy
无助于解决问题,它是dict.fromkeys
功能。
来自 https://docs.python.org/3/library/stdtypes.html#dict.fromkeys 的文档
所有值仅引用一个实例,因此值作为可变对象(例如空列表)通常没有意义。要获得不同的值,请使用字典理解。
您将单个列表传递给 fromkeys 作为 value 参数。它仍然只是一个列表
所以看来你的字典理解是推荐的方法。