奇怪的Python字典行为

3

有人能为我解释一下这种行为吗?

mapping = dict.fromkeys([1, 2, 3], [])
objects = [{'pk': 1}, {'pk': 2}, {'pk': 3}]

for obj in objects:
    pk = obj['pk']
    mapping[pk].append(obj)

print mapping

# expected: {1: [{'pk': 1}], 2: [{'pk': 2}], 3: [{'pk': 3}]}
# got: {1: [{'pk': 1}, {'pk': 2}, {'pk': 3}], 2: [{'pk': 1}, {'pk': 2}, {'pk': 3}], 3: [{'pk': 1}, {'pk': 2}, {'pk': 3}]}

我试图将objects中的字典映射到另一个字典,其键是原始字典的属性。假设objects列表包含每个唯一PK的多个对象(我不仅仅在这里使用map的原因)。

4个回答

5

这是因为在:

  mapping = dict.fromkeys([1, 2, 3], [])

[] 只被计算一次,所以每个键都有同样的列表值。尝试使用 collections.defaultdict 替代。


1
谢谢。(我会在8分钟后接受答案,原因不明) - Aaron

1
如果您将mapping更改如下:
from collections import defaultdict
mapping = defaultdict(list)

保留其余部分不变,代码将按预期执行。

您当前代码的问题在于mapping的所有三个键都映射到同一个列表。当您向其中一个附加元素时,实际上是向所有元素附加。


1

这是因为在这一行中:

mapping = dict.fromkeys([1, 2, 3], [])

你将同一个列表分配给每个键。由于列表是可变的,因此通过为一个键修改列表,您同时修改了其他键的列表。


1
在第一行中,使用表达式[]会创建一个空列表。
这是上面片段中唯一出现的空列表对象。当dict.fromkeys运行时,它不会创建三个不同的空列表副本。相反,它会创建对同一个空列表的三个引用。
因此,在稍后的循环中,每次将另一个数字添加到空列表中时,它都是同一个列表。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接