【问题标题】:Calculate difference in keys contained in two Python dictionaries计算两个 Python 字典中包含的键的差异
【发布时间】:2010-11-13 00:21:43
【问题描述】:

假设我有两个 Python 字典 - dictAdictB。我需要找出dictB 中是否存在任何键,但dictA 中是否存在键。最快的方法是什么?

我应该把字典键转换成一个集合然后继续吗?

有兴趣了解你的想法……


感谢您的回复。

很抱歉没有正确地陈述我的问题。 我的场景是这样的 - 我有一个 dictA,它可以与 dictB 相同,或者与 dictB 相比可能缺少一些键,否则某些键的值可能不同,必须设置为dictA 键的值。

问题是字典没有标准,可以有可以是dict的dict的值。

dictA={'key1':a, 'key2':b, 'key3':{'key11':cc, 'key12':dd}, 'key4':{'key111':{....}}}
dictB={'key1':a, 'key2:':newb, 'key3':{'key11':cc, 'key12':newdd, 'key13':ee}.......

所以'key2'值必须重置为新值,'key13'必须添加到字典中。 键值没有固定格式。它可以是一个简单的值,也可以是一个字典或字典的字典。

【问题讨论】:

    标签: python dictionary


    【解决方案1】:

    您可以对键使用 set 操作:

    diff = set(dictb.keys()) - set(dicta.keys())
    

    这是一个查找所有可能性的类:添加了什么,删除了什么,哪些键值对是相同的,哪些键值对改变了。

    class DictDiffer(object):
        """
        Calculate the difference between two dictionaries as:
        (1) items added
        (2) items removed
        (3) keys same in both but changed values
        (4) keys same in both and unchanged values
        """
        def __init__(self, current_dict, past_dict):
            self.current_dict, self.past_dict = current_dict, past_dict
            self.set_current, self.set_past = set(current_dict.keys()), set(past_dict.keys())
            self.intersect = self.set_current.intersection(self.set_past)
        def added(self):
            return self.set_current - self.intersect 
        def removed(self):
            return self.set_past - self.intersect 
        def changed(self):
            return set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o])
        def unchanged(self):
            return set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o])
    

    这是一些示例输出:

    >>> a = {'a': 1, 'b': 1, 'c': 0}
    >>> b = {'a': 1, 'b': 2, 'd': 0}
    >>> d = DictDiffer(b, a)
    >>> print "Added:", d.added()
    Added: set(['d'])
    >>> print "Removed:", d.removed()
    Removed: set(['c'])
    >>> print "Changed:", d.changed()
    Changed: set(['b'])
    >>> print "Unchanged:", d.unchanged()
    Unchanged: set(['a'])
    

    作为 github 存储库提供: https://github.com/hughdbrown/dictdiffer

    【讨论】:

    • 智能解决方案,谢谢!我通过检查更改或未更改的值是否是 dict 实例并调用递归函数以使用您的类再次检查它们,使它与嵌套 dicts 一起使用。
    • @AJJ 我很想看到这个实现。
    • def update(self, new_dict): self.__init__(new_dict, self.current_dict) 之类的怎么样,这样您就可以进行滚动比较
    • 一些备注:DictDiffer 类是一个无状态类,可以是一个函数。 changedunchanged 值可以在同一个循环中计算。这两个函数可以返回list 而不是set,这肯定更便宜。深入对比可以看一下单元测试框架:docs.python.org/2/library/unittest.html,按照源码中的assertDictEqual方法即可。
    • FWIW,set(dictb) 可能比set(dictb.keys()) 更好。
    【解决方案2】:

    如果您想要递归地区分,我已经为 python 编写了一个包: https://github.com/seperman/deepdiff

    安装

    从 PyPi 安装:

    pip install deepdiff
    

    示例用法

    导入

    >>> from deepdiff import DeepDiff
    >>> from pprint import pprint
    >>> from __future__ import print_function # In case running on Python 2
    

    相同的对象返回空

    >>> t1 = {1:1, 2:2, 3:3}
    >>> t2 = t1
    >>> print(DeepDiff(t1, t2))
    {}
    

    项目类型已更改

    >>> t1 = {1:1, 2:2, 3:3}
    >>> t2 = {1:1, 2:"2", 3:3}
    >>> pprint(DeepDiff(t1, t2), indent=2)
    { 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
                                     'newvalue': '2',
                                     'oldtype': <class 'int'>,
                                     'oldvalue': 2}}}
    

    物品的价值发生了变化

    >>> t1 = {1:1, 2:2, 3:3}
    >>> t2 = {1:1, 2:4, 3:3}
    >>> pprint(DeepDiff(t1, t2), indent=2)
    {'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}
    

    添加和/或删除项目

    >>> t1 = {1:1, 2:2, 3:3, 4:4}
    >>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
    >>> ddiff = DeepDiff(t1, t2)
    >>> pprint (ddiff)
    {'dic_item_added': ['root[5]', 'root[6]'],
     'dic_item_removed': ['root[4]'],
     'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}
    

    字符串区别

    >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
    >>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
    >>> ddiff = DeepDiff(t1, t2)
    >>> pprint (ddiff, indent = 2)
    { 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
                          "root[4]['b']": { 'newvalue': 'world!',
                                            'oldvalue': 'world'}}}
    

    字符串差异2

    >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
    >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
    >>> ddiff = DeepDiff(t1, t2)
    >>> pprint (ddiff, indent = 2)
    { 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
                                                    '+++ \n'
                                                    '@@ -1,5 +1,4 @@\n'
                                                    '-world!\n'
                                                    '-Goodbye!\n'
                                                    '+world\n'
                                                    ' 1\n'
                                                    ' 2\n'
                                                    ' End',
                                            'newvalue': 'world\n1\n2\nEnd',
                                            'oldvalue': 'world!\n'
                                                        'Goodbye!\n'
                                                        '1\n'
                                                        '2\n'
                                                        'End'}}}
    
    >>> 
    >>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
    --- 
    +++ 
    @@ -1,5 +1,4 @@
    -world!
    -Goodbye!
    +world
     1
     2
     End
    

    类型改变

    >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
    >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
    >>> ddiff = DeepDiff(t1, t2)
    >>> pprint (ddiff, indent = 2)
    { 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
                                          'newvalue': 'world\n\n\nEnd',
                                          'oldtype': <class 'list'>,
                                          'oldvalue': [1, 2, 3]}}}
    

    列表差异

    >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
    >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
    >>> ddiff = DeepDiff(t1, t2)
    >>> pprint (ddiff, indent = 2)
    {'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}
    

    列出差异2:

    >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
    >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
    >>> ddiff = DeepDiff(t1, t2)
    >>> pprint (ddiff, indent = 2)
    { 'iterable_item_added': {"root[4]['b'][3]": 3},
      'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
                          "root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}
    

    忽略顺序或重复列出差异:(使用与上述相同的字典)

    >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
    >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
    >>> ddiff = DeepDiff(t1, t2, ignore_order=True)
    >>> print (ddiff)
    {}
    

    包含字典的列表:

    >>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
    >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
    >>> ddiff = DeepDiff(t1, t2)
    >>> pprint (ddiff, indent = 2)
    { 'dic_item_removed': ["root[4]['b'][2][2]"],
      'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}
    

    套装:

    >>> t1 = {1, 2, 8}
    >>> t2 = {1, 2, 3, 5}
    >>> ddiff = DeepDiff(t1, t2)
    >>> pprint (DeepDiff(t1, t2))
    {'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}
    

    命名元组:

    >>> from collections import namedtuple
    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> t1 = Point(x=11, y=22)
    >>> t2 = Point(x=11, y=23)
    >>> pprint (DeepDiff(t1, t2))
    {'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}
    

    自定义对象:

    >>> class ClassA(object):
    ...     a = 1
    ...     def __init__(self, b):
    ...         self.b = b
    ... 
    >>> t1 = ClassA(1)
    >>> t2 = ClassA(2)
    >>> 
    >>> pprint(DeepDiff(t1, t2))
    {'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
    

    添加了对象属性:

    >>> t2.c = "new attribute"
    >>> pprint(DeepDiff(t1, t2))
    {'attribute_added': ['root.c'],
     'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
    

    【讨论】:

    • 谢谢你!刚刚在我的项目中实施,效果很好!
    • @gtalarico 乐于助人!谢谢你的好话!
    • 有什么选项可以忽略list order的不同吗?因为我的应用程序并不关心它。
    • 不错的项目,在我身边以最小的努力完成了所有工作。谢谢!
    • @LeiYang 是的,你可以设置ignore_order=True。您可以在 deepdiff.readthedocs.io/en/latest/diff.html 找到文档
    【解决方案3】:

    不确定它是否“快”,但通常可以做到这一点

    dicta = {"a":1,"b":2,"c":3,"d":4}
    dictb = {"a":1,"d":2}
    for key in dicta.keys():
        if not key in dictb:
            print key
    

    【讨论】:

    • 你必须交换dictadictb,因为他想知道那些不在dicta中的dictb的键。
    • for key in dicta.keys(): => for key in dicta:
    【解决方案4】:

    正如 Alex Martelli 所写,如果您只是想检查 B 中的任何键是否不在 A 中,any(True for k in dictB if k not in dictA) 将是可行的方法。

    要查找丢失的键:

    diff = set(dictB)-set(dictA) #sets
    
    C:\Dokumente und Einstellungen\thc>python -m timeit -s "dictA =    
    dict(zip(range(1000),range
    (1000))); dictB = dict(zip(range(0,2000,2),range(1000)))" "diff=set(dictB)-set(dictA)"
    10000 loops, best of 3: 107 usec per loop
    
    diff = [ k for k in dictB if k not in dictA ] #lc
    
    C:\Dokumente und Einstellungen\thc>python -m timeit -s "dictA = 
    dict(zip(range(1000),range
    (1000))); dictB = dict(zip(range(0,2000,2),range(1000)))" "diff=[ k for k in dictB if
    k not in dictA ]"
    10000 loops, best of 3: 95.9 usec per loop
    

    所以这两种解决方案的速度几乎相同。

    【讨论】:

    • 这更有意义:any(k not in dictA for k in dictB)
    【解决方案5】:

    如果你的意思真的是你所说的(你只需要找出如果 B 中“有任何键”而不是 A 中的“有任何键”,而不是那些可能有的话),最快的方法应该是:

    if any(True for k in dictB if k not in dictA): ...
    

    如果您确实需要找出哪些键(如果有)在 B 中而不在 A 中,而不仅仅是“如果”有这样的键,那么现有答案是非常合适的(但我确实建议将来更精确问题是否确实是您的意思;-)。

    【讨论】:

      【解决方案6】:

      The top answer by hughdbrown 建议使用设置差异,这绝对是最好的方法:

      diff = set(dictb.keys()) - set(dicta.keys())
      

      此代码的问题在于它构建两个列表只是为了创建两个集合,因此浪费了 4N 时间和 2N 空间。它也比它需要的复杂一点。

      通常,这没什么大不了的,但如果是的话:

      diff = dictb.keys() - dicta
      

      Python 2

      在 Python 2 中,keys() 返回键列表,而不是 KeysView。所以你必须直接询问viewkeys()

      diff = dictb.viewkeys() - dicta
      

      对于双版本 2.7/3.x 代码,您希望使用six 或类似的东西,因此您可以使用six.viewkeys(dictb)

      diff = six.viewkeys(dictb) - dicta
      

      在 2.4-2.6 中,没有 KeysView。但是您至少可以通过直接从迭代器构建左集而不是先构建列表来将成本从 4N 降低到 N:

      diff = set(dictb) - dicta
      

      项目

      我有一个 dictA,它可以与 dictB 相同,或者与 dictB 相比可能缺少某些键,否则某些键的值可能不同

      所以你真的不需要比较键,而是项目。 ItemsView 只是一个 Set 如果值是可散列的,就像字符串一样。如果是,那很容易:

      diff = dictb.items() - dicta.items()
      

      递归差异

      虽然问题不是直接要求递归 diff,但一些示例值是 dicts,并且看起来预期的输出确实递归地对它们进行了diff。这里已经有多个答案展示了如何做到这一点。

      【讨论】:

      • 2018年的明确答案。
      • @Jean-FrançoisFabre 当然,Python 2.4-2.6 的东西在 2018 年已经相当无关紧要了……
      • 有些人坚持使用 2.6
      【解决方案7】:

      Use set():

      set(dictA.keys()).intersection(dictB.keys())
      

      【讨论】:

      • set(d) 已经只返回了键,所以你可以这样做 set(da).intersection(db)
      【解决方案8】:

      还有另一个question in stackoverflow about this argument,我不得不承认解释了一个简单的解决方案:python 的datadiff library 有助于打印两个字典之间的差异。

      【讨论】:

        【解决方案9】:

        这是一种可行的方法,允许计算结果为False 的键,并且如果可能的话,仍然使用生成器表达式提前退出。虽然不是特别漂亮。

        any(map(lambda x: True, (k for k in b if k not in a)))
        

        编辑:

        THC4k 回复了我对另一个答案的评论。这是一种更好、更漂亮的方式来完成上述操作:

        any(True for k in b if k not in a)
        

        不知道我是怎么想到的……

        【讨论】:

        • 这与之前 Alex Martelli 的答案相同
        • 现在是。当我发布它时(九年前,哈哈),较早的答案是any(k for k in dictB if k not in dictA),这不是一回事(对于假键)。检查编辑历史记录/时间戳。
        【解决方案10】:

        这是一个老问题,比我需要的要少一点,所以这个答案实际上比这个问题解决的问题更多。这个问题的答案帮助我解决了以下问题:

        1. (询问)记录两个字典之间的差异
        2. 将 #1 中的差异合并到基本字典中
        3. (问)合并两个字典之间的差异(将字典 #2 视为差异字典)
        4. 尝试检测项目的移动和变化
        5. (询问)递归地执行所有这些操作

        所有这些与 JSON 相结合,构成了非常强大的配置存储支持。

        解决方案(also on github):

        from collections import OrderedDict
        from pprint import pprint
        
        
        class izipDestinationMatching(object):
            __slots__ = ("attr", "value", "index")
        
            def __init__(self, attr, value, index):
                self.attr, self.value, self.index = attr, value, index
        
            def __repr__(self):
                return "izip_destination_matching: found match by '%s' = '%s' @ %d" % (self.attr, self.value, self.index)
        
        
        def izip_destination(a, b, attrs, addMarker=True):
            """
            Returns zipped lists, but final size is equal to b with (if shorter) a padded with nulls
            Additionally also tries to find item reallocations by searching child dicts (if they are dicts) for attribute, listed in attrs)
            When addMarker == False (patching), final size will be the longer of a, b
            """
            for idx, item in enumerate(b):
                try:
                    attr = next((x for x in attrs if x in item), None)  # See if the item has any of the ID attributes
                    match, matchIdx = next(((orgItm, idx) for idx, orgItm in enumerate(a) if attr in orgItm and orgItm[attr] == item[attr]), (None, None)) if attr else (None, None)
                    if match and matchIdx != idx and addMarker: item[izipDestinationMatching] = izipDestinationMatching(attr, item[attr], matchIdx)
                except:
                    match = None
                yield (match if match else a[idx] if len(a) > idx else None), item
            if not addMarker and len(a) > len(b):
                for item in a[len(b) - len(a):]:
                    yield item, item
        
        
        def dictdiff(a, b, searchAttrs=[]):
            """
            returns a dictionary which represents difference from a to b
            the return dict is as short as possible:
              equal items are removed
              added / changed items are listed
              removed items are listed with value=None
            Also processes list values where the resulting list size will match that of b.
            It can also search said list items (that are dicts) for identity values to detect changed positions.
              In case such identity value is found, it is kept so that it can be re-found during the merge phase
            @param a: original dict
            @param b: new dict
            @param searchAttrs: list of strings (keys to search for in sub-dicts)
            @return: dict / list / whatever input is
            """
            if not (isinstance(a, dict) and isinstance(b, dict)):
                if isinstance(a, list) and isinstance(b, list):
                    return [dictdiff(v1, v2, searchAttrs) for v1, v2 in izip_destination(a, b, searchAttrs)]
                return b
            res = OrderedDict()
            if izipDestinationMatching in b:
                keepKey = b[izipDestinationMatching].attr
                del b[izipDestinationMatching]
            else:
                keepKey = izipDestinationMatching
            for key in sorted(set(a.keys() + b.keys())):
                v1 = a.get(key, None)
                v2 = b.get(key, None)
                if keepKey == key or v1 != v2: res[key] = dictdiff(v1, v2, searchAttrs)
            if len(res) <= 1: res = dict(res)  # This is only here for pretty print (OrderedDict doesn't pprint nicely)
            return res
        
        
        def dictmerge(a, b, searchAttrs=[]):
            """
            Returns a dictionary which merges differences recorded in b to base dictionary a
            Also processes list values where the resulting list size will match that of a
            It can also search said list items (that are dicts) for identity values to detect changed positions
            @param a: original dict
            @param b: diff dict to patch into a
            @param searchAttrs: list of strings (keys to search for in sub-dicts)
            @return: dict / list / whatever input is
            """
            if not (isinstance(a, dict) and isinstance(b, dict)):
                if isinstance(a, list) and isinstance(b, list):
                    return [dictmerge(v1, v2, searchAttrs) for v1, v2 in izip_destination(a, b, searchAttrs, False)]
                return b
            res = OrderedDict()
            for key in sorted(set(a.keys() + b.keys())):
                v1 = a.get(key, None)
                v2 = b.get(key, None)
                #print "processing", key, v1, v2, key not in b, dictmerge(v1, v2)
                if v2 is not None: res[key] = dictmerge(v1, v2, searchAttrs)
                elif key not in b: res[key] = v1
            if len(res) <= 1: res = dict(res)  # This is only here for pretty print (OrderedDict doesn't pprint nicely)
            return res
        

        【讨论】:

          【解决方案11】:

          标准怎么样(比较完整对象)

          PyDev->新建 PyDev 模块->模块:单元测试

          import unittest
          
          
          class Test(unittest.TestCase):
          
          
              def testName(self):
                  obj1 = {1:1, 2:2}
                  obj2 = {1:1, 2:2}
                  self.maxDiff = None # sometimes is usefull
                  self.assertDictEqual(d1, d2)
          
          if __name__ == "__main__":
              #import sys;sys.argv = ['', 'Test.testName']
          
              unittest.main()
          

          【讨论】:

          • 如果你有一个巨大的嵌套字典并且你想比较里面的每一个东西并查看差异,那就太好了。谢谢!
          【解决方案12】:

          如果 Python ≥ 2.7:

          # update different values in dictB
          # I would assume only dictA should be updated,
          # but the question specifies otherwise
          
          for k in dictA.viewkeys() & dictB.viewkeys():
              if dictA[k] != dictB[k]:
                  dictB[k]= dictA[k]
          
          # add missing keys to dictA
          
          dictA.update( (k,dictB[k]) for k in dictB.viewkeys() - dictA.viewkeys() )
          

          【讨论】:

            【解决方案13】:

            这里是深度比较 2 个字典键的解决方案:

            def compareDictKeys(dict1, dict2):
              if type(dict1) != dict or type(dict2) != dict:
                  return False
            
              keys1, keys2 = dict1.keys(), dict2.keys()
              diff = set(keys1) - set(keys2) or set(keys2) - set(keys1)
            
              if not diff:
                  for key in keys1:
                      if (type(dict1[key]) == dict or type(dict2[key]) == dict) and not compareDictKeys(dict1[key], dict2[key]):
                          diff = True
                          break
            
              return not diff
            

            【讨论】:

              【解决方案14】:

              这是一个可以比较两个以上字典的解决方案:

              def diff_dict(dicts, default=None):
                  diff_dict = {}
                  # add 'list()' around 'd.keys()' for python 3 compatibility
                  for k in set(sum([d.keys() for d in dicts], [])):
                      # we can just use "values = [d.get(k, default) ..." below if 
                      # we don't care that d1[k]=default and d2[k]=missing will
                      # be treated as equal
                      if any(k not in d for d in dicts):
                          diff_dict[k] = [d.get(k, default) for d in dicts]
                      else:
                          values = [d[k] for d in dicts]
                          if any(v != values[0] for v in values):
                              diff_dict[k] = values
                  return diff_dict
              

              用法示例:

              import matplotlib.pyplot as plt
              diff_dict([plt.rcParams, plt.rcParamsDefault, plt.matplotlib.rcParamsOrig])
              

              【讨论】:

                【解决方案15】:

                我的两个字典之间的对称差异的秘诀:

                def find_dict_diffs(dict1, dict2):
                    unequal_keys = []
                    unequal_keys.extend(set(dict1.keys()).symmetric_difference(set(dict2.keys())))
                    for k in dict1.keys():
                        if dict1.get(k, 'N\A') != dict2.get(k, 'N\A'):
                            unequal_keys.append(k)
                    if unequal_keys:
                        print 'param', 'dict1\t', 'dict2'
                        for k in set(unequal_keys):
                            print str(k)+'\t'+dict1.get(k, 'N\A')+'\t '+dict2.get(k, 'N\A')
                    else:
                        print 'Dicts are equal'
                
                dict1 = {1:'a', 2:'b', 3:'c', 4:'d', 5:'e'}
                dict2 = {1:'b', 2:'a', 3:'c', 4:'d', 6:'f'}
                
                find_dict_diffs(dict1, dict2)
                

                结果是:

                param   dict1   dict2
                1       a       b
                2       b       a
                5       e       N\A
                6       N\A     f
                

                【讨论】:

                  【解决方案16】:

                  正如在其他答案中提到的,unittest 为比较 dicts 产生了一些不错的输出,但在这个例子中,我们不想先构建一个完整的测试。

                  抓取单元测试源,看起来您可以通过以下方式获得公平的解决方案:

                  import difflib
                  import pprint
                  
                  def diff_dicts(a, b):
                      if a == b:
                          return ''
                      return '\n'.join(
                          difflib.ndiff(pprint.pformat(a, width=30).splitlines(),
                                        pprint.pformat(b, width=30).splitlines())
                      )
                  

                  所以

                  dictA = dict(zip(range(7), map(ord, 'python')))
                  dictB = {0: 112, 1: 'spam', 2: [1,2,3], 3: 104, 4: 111}
                  print diff_dicts(dictA, dictB)
                  

                  结果:

                  {0: 112,
                  -  1: 121,
                  -  2: 116,
                  +  1: 'spam',
                  +  2: [1, 2, 3],
                     3: 104,
                  -  4: 111,
                  ?        ^
                  
                  +  4: 111}
                  ?        ^
                  
                  -  5: 110}
                  

                  地点:

                  • '-' 表示第一个但不是第二个字典中的键/值
                  • '+' 表示第二个而不是第一个字典中的键/值

                  就像在 unittest 中一样,唯一需要注意的是,由于尾随的逗号/括号,最终的映射可以被认为是一个差异。

                  【讨论】:

                    【解决方案17】:

                    试试这个找到de intersection,两个字典中的键,如果你想在第二个字典中找不到键,只需使用not in...

                    intersect = filter(lambda x, dictB=dictB.keys(): x in dictB, dictA.keys())
                    

                    【讨论】:

                      【解决方案18】:

                      @Maxx 有一个很好的答案,使用 Python 提供的unittest 工具:

                      import unittest
                      
                      
                      class Test(unittest.TestCase):
                          def runTest(self):
                              pass
                      
                          def testDict(self, d1, d2, maxDiff=None):
                              self.maxDiff = maxDiff
                              self.assertDictEqual(d1, d2)
                      

                      然后,您可以在代码中的任何位置调用:

                      try:
                          Test().testDict(dict1, dict2)
                      except Exception, e:
                          print e
                      

                      生成的输出看起来像来自 diff 的输出,漂亮地打印字典,每个不同的行前加上 +-

                      【讨论】:

                        【解决方案19】:

                        不确定它是否仍然相关但我遇到了这个问题,我的情况是我只需要返回所有嵌套字典等的更改字典等。找不到一个好的解决方案,但我确实结束了@ 987654321@。希望对你有帮助,

                        【讨论】:

                        • 最好在答案中使用最少的代码来修复 OP 的问题,而不是链接。如果链接失效或移动,您的答案将变得毫无用处。
                        【解决方案20】:

                        如果您想要一个内置解决方案来与任意 dict 结构进行全面比较,@Maxx 的答案是一个好的开始。

                        import unittest
                        
                        test = unittest.TestCase()
                        test.assertEqual(dictA, dictB)
                        

                        【讨论】:

                        • 你显然不能像那样实例化一个测试类,这太糟糕了。
                        【解决方案21】:

                        根据ghostdog74的回答,

                        dicta = {"a":1,"d":2}
                        dictb = {"a":5,"d":2}
                        
                        for value in dicta.values():
                            if not value in dictb.values():
                                print value
                        

                        将打印不同的dicta值

                        【讨论】:

                          猜你喜欢
                          • 2016-03-21
                          • 2019-10-06
                          • 1970-01-01
                          • 2020-04-13
                          • 1970-01-01
                          • 2011-08-19
                          • 2011-01-25
                          • 1970-01-01
                          相关资源
                          最近更新 更多