Python:为什么每个键添加dict值取决于顺序?

Python:为什么每个键添加dict值取决于顺序?,python,dictionary,Python,Dictionary,假设您有几个字典跟踪每个键(在子目录中)的三个浮点值。您希望能够以添加多个dict中存在的键的值的方式合并这些字典 使用普通dict更新时,值会被覆盖,因此您可以将dict()子类化为: 然后,您将要合并/添加到普通dict键中的dict: # Small example data that reproduces the error few_statements = {} few_statements['linkedin'] = {u'Homerun': {u'skill': 14.0,

假设您有几个字典跟踪每个键(在子目录中)的三个浮点值。您希望能够以添加多个dict中存在的键的值的方式合并这些字典

使用普通dict更新时,值会被覆盖,因此您可以将
dict()子类化为:

然后,您将要合并/添加到普通dict键中的dict:

# Small example data that reproduces the error
few_statements = {}
few_statements['linkedin'] = {u'Homerun': {u'skill': 14.0,
                                           u'knowledge': 34.0,
                                           u'interest': 20.0}}
few_statements['tudelft'] = {u'Presentation': {u'skill': 14.0,
                                               u'knowledge': 34.0,
                                               u'interest': 20.0},
                             u'Future': {u'skill': 16.0,
                                         u'knowledge': 25.33,
                                         u'interest': 2.0},
                             u'Visual_perception': {u'skill': 20.46,
                                                    u'knowledge': 28.35,
                                                    u'interest': 4.0}}
few_statements['website'] = {u'Homerun': {u'skill': 1.0,
                                          u'knowledge': 3.0,
                                          u'interest': 2.0}}

few_statements['shareworks'] = {u'Presentation': {u'skill': 8.0,
                                                  u'knowledge': 20.0,
                                                  u'interest': 12.0},
                                u'Future': {u'skill': 17.0,
                                            u'knowledge': 26.33,
                                            u'interest': 3.0},
                                u'Visual_perception': {u'skill': 2.0,
                                                       u'knowledge': 3.0,
                                                       u'interest': 6.0}}
现在我们应该能够将这些键、值对逐个添加到
StatementDict()
中,或者使用
StatementDict.update()方法。源dict添加到语句dict的顺序对结果不重要

# First we try updating in one order
small_test1a = StatementDict()
for origin in ("tudelft", "website", "linkedin", "shareworks"):
    for st in few_statements[origin].iteritems():
        small_test1a.add(st)

# And then in another order
small_test2 = StatementDict()
for origin in ("linkedin", "shareworks", "tudelft", "website"):
    for st in few_statements[origin].iteritems():
        small_test2.add(st)

print "Different order, same result?", small_test1a == small_test2
                                                # False, but why?
for key in small_test1a:
    print "Desired:", key, small_test1a[key]
    print "Unexpected:", key, small_test2[key]
唉,添加命令的顺序确实会影响结果。但为什么,以及意外的结果发生了什么

Desired: Future {u'skill': 33.0, u'knowledge': 51.66, u'interest': 5.0}
Unexpected: Future {u'skill': 50.0, u'knowledge': 77.99, u'interest': 8.0}
Desired: Presentation {u'skill': 22.0, u'knowledge': 54.0, u'interest': 32.0}
Unexpected: Presentation {u'skill': 30.0, u'knowledge': 74.0, u'interest': 44.0}
Desired: Homerun {u'skill': 15.0, u'knowledge': 37.0, u'interest': 22.0}
Unexpected: Homerun {u'skill': 29.0, u'knowledge': 71.0, u'interest': 42.0}
Desired: Visual_perception {u'skill': 22.46, u'knowledge': 31.35, u'interest': 10.0}
Unexpected: Visual_perception {u'skill': 24.46, u'knowledge': 34.35, u'interest': 16.0}
以第二个顺序添加dict似乎会使第一个dict的值加倍(添加两次?)。我不明白为什么会这样。如何使期望的加法行为可靠地发生,而不受加法顺序的影响

还有一件事我不明白:当我创建一个新的
语句dict()
并用相同的值填充它时,
small_test1a
的值为什么会改变

运行以下行会导致
small_test1a
在循环的最终迭代中发生更改:

small_test1b = StatementDict()
for origin in ("tudelft", "website", "linkedin", "shareworks"):
    small_test1b.update(few_statements[origin])
print "\nDoes .update() function?", small_test1a == small_test1b
print small_test1a
顺便说一下,根据我的实际数据,根本没有添加任何内容。而是保留第一个放置的值。这与更新普通dict(其中值被覆盖)不同。不幸的是,我无法用少量的测试数据重现这种行为。

当您这样做时:

self[ann_id] = lvl_dict
您为该特定词典取另一个名称(例如,表示“tudelft”的名称)。然后,在执行后续操作时:

self[ann_id]['skill'] += lvl_dict['skill']
您可以在当前的基础上修改先前的
lvl_dict
(即,在本例中,在“网站”的基础上更改“tudelft”的版本)

对此的最小修复是第一本字典。但是,我可能会尝试使用
collections.defaultdict
,这样您就可以完全消除self:
测试中的
if ann\u id。当defaultdict创建新字典时,它将是一个新实例,因此不会修改任何现有实例


在下面的注释中使用
defaultdict
和lambda函数的示例:

from collections import defaultdict

class StatementDict(defaultdict):
    def __init__(self):
        defaultdict.__init__(self,
            lambda: {'skill': 0.0, 'knowledge': 0.0, 'interest': 0.0})

    def add(self, statement):
        ... as before ...

谢谢你提醒我复印!我以前在使用字典时犯过好几次这样的错误,所以我对自己现在还没有理解感到有点失望。然而,使用
集合.defaultdict
似乎不那么简单。我试图将其子类化为
StatementDict(defaultdict(lvl_dict_factory))
,其中
lvl_dict_factory=lambda:{'skill':0.0,'knowledge':0.0,'interest':0.0}
,但显然不是这样做的。啊,调用它的方式不对。如果您有
类StatementDict(defaultdict)
您可以创建一个实例,例如
small\u test1a=StatementDict(lvl\u dict\u factory)
。或者,提供您自己的
\uuuuu init\uuuuu
,这对您来说可能看起来/感觉更干净;我将在一个示例中进行编辑。
from collections import defaultdict

class StatementDict(defaultdict):
    def __init__(self):
        defaultdict.__init__(self,
            lambda: {'skill': 0.0, 'knowledge': 0.0, 'interest': 0.0})

    def add(self, statement):
        ... as before ...