2012-02-03 109 views
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)。

回答

5

这是因为:

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

[]计算一次,所以每个按键都有相同的列表的价值。请尝试使用collections.defaultdict

+1

:facepalm:谢谢。 (由于某种原因,我会在8分钟内接受答案) – Aaron 2012-02-03 09:19:41

1

如果更改mapping如下:

from collections import defaultdict 
mapping = defaultdict(list) 

,并保持休息原样,代码会做你的期望。

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

1

它发生,因为在这一行:

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

你分配相同的列表,每个键。而且因为列表是可变的,所以通过修改一个键的列表,你可以同时修改其他键的列表。

1

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

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

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