from collections import defaultdict
phn_dictionary = {"actual": [], "predicted": []}
phn_dict = defaultdict(lambda: phn_dictionary)
phn_dict["qwe"]["actual"].extend([123,456])
phn_dict
>>>defaultdict(<function __main__.<lambda>>,
{'qwe': {'actual': [123, 456], 'predicted': []}})
phn_dict["asd"]["actual"].extend([123,456])
phn_dict
>>>defaultdict(<function __main__.<lambda>>,
{'asd': {'actual': [123, 456, 123, 456], 'predicted': []},
'qwe': {'actual': [123, 456, 123, 456], 'predicted': []}})
我正在运行Python 3.6.4 64位。我需要使用一个defaultdict来生成phn_dictionary作为其默认值,如上面的代码所示。 我事先并不知道&#34; asd&#34;和&#34; qwe&#34;我将访问。可以看出,在我延伸到&#34; asd&#34; &#34;实际&#34; asd和qwe的关键是扩展。这是一个错误还是我做错了什么?
答案 0 :(得分:3)
问题是lambda: phn_dictionary
是一个返回phn_dictionary
的函数 - 完全相同的字典对象 - 每次调用它时。因此,您最终得到的字典与一堆键的值相同。每次通过一个键追加时,所有其他键都可以看到。
你想要的不是这本词典,而是一本以该词典副本开头的新词典。正如Brendan Abel在评论中指出的那样,你可能想要一个深副本 - 不只是一个新的dict,而是一个带有新列表的新dict:
phn_dict = defaultdict(lambda: copy.deepcopy(phn_dictionary))
或者,这可能更清楚(依赖于原始列表应该始终为空的事实):
phn_dict = defaultdict(lambda: {key: [] for key in phn_dictionary})
或者,如果除了这里你不需要phn_dictionary
,只需使用Brendan的答案并在函数中从头开始创建dict:
phn_dict = defaultdict(lambda: {"actual": [], "predicted": []})
如果这是一个精简样本,并且真正的dict要大得多,或者变量等等,显然最后一个版本将不起作用,但如果这是真正的代码,那么它是最简单的。
还有其他方法可以解决这个问题,其中一些方法可能更清晰,但这是最符合内联lambda的方法,它似乎与你的思维方式相符。
答案 1 :(得分:1)
这是因为他们都代表同一个字典。如果您将工厂定义为返回字典文字,则可以解决问题
phn_dict = defaultdict(lambda: {"actual": [], "predicted": []})
这是因为每个时间调用默认的工厂lambda,它会返回一个新的字典,而不是一遍又一遍地返回相同的字典。
或者,您可以使用copy.deepcopy
phn_dict = defaultdict(lambda: copy.deepcopy(phn_dictionary))
这将复制定义的字典和所有内部值。
答案 2 :(得分:0)
其他答案指出重用内部列表的引用。
除非确实想要提出KeyError
如果对象使用了错误的密钥,否则你可以使用默认的listdict:
from collections import defaultdict
phn_dict = defaultdict(lambda: defaultdict(list))
phn_dict["qwe"]["actual"].extend([123,456])
phn_dict["qwe"]["predicted"].extend([768,333])
print(dict(phn_dict)) # clearer repr
结果:
{'qwe': defaultdict(<class 'list'>, {'actual': [123, 456], 'predicted': [768, 333]})}