奇怪的python dict行为

时间:2012-02-03 09:13:32

标签: python dictionary

有人可以为我解释这种行为吗?

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 个答案:

答案 0 :(得分:5)

那是因为在:

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

[]被评估一次,因此每个键与值具有相同的列表。请尝试使用collections.defaultdict

答案 1 :(得分:1)

如果按以下方式更改mapping

from collections import defaultdict
mapping = defaultdict(list)

并按原样保留其余部分,代码将按预期执行。

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

答案 2 :(得分:1)

它发生了,因为在这一行中:

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

为每个键分配相同的列表。并且由于列表是可变的,通过修改一个键的列表,您可以同时修改其他键的列表。

答案 3 :(得分:1)

在第1行,使用表达式[]会导致创建一个空列表。

这是上面代码段中出现的唯一空列表对象。当dict.fromkeys运行时,它不会为空列表创建三个不同的副本。相反,它对SAME空列表进行了三次引用。

因此,在稍后的循环中,每次在空列表中添加另一个数字时,它都是相同的列表。