【问题标题】:Print diff of Python dictionariesPython 字典的打印差异
【发布时间】:2012-10-09 01:08:09
【问题描述】:

我想获取两个字典并打印它们的差异。此差异应包括键和值的差异。我创建了这个小 sn-p 以使用 unittest 模块中的内置代码来实现结果。但是,这是一个讨厌的 hack,因为我必须继承 unittest.TestCase 并提供一个 runtest() 方法才能使其工作。此外,此代码将导致应用程序出错,因为它会在存在差异时引发AssertError。我真正想要的只是打印差异。

import unittest
class tmp(unittest.TestCase):
    def __init__(self):
         # Show full diff of objects (dicts could be HUGE and output truncated)
        self.maxDiff = None
    def runTest():
        pass
_ = tmp()
_.assertDictEqual(d1, d2)

我希望使用difflib 模块,但它看起来只适用于字符串。有什么办法可以解决这个问题并且仍然使用difflib

【问题讨论】:

  • @MarkReed -- 这是不同的。这要求 keys 的差异,这要求 keysvalues 的差异(我假设 OP 需要 key-value 对)——例如{1:2, 2:3}{1:3,2:2} 不同,但实际上并没有明确说明...
  • @mgilson - 我没有提出关闭请求或将其标记为重复,但如果您查看该页面上接受的答案,它包括值比较,而不仅仅是键集比较。
  • 我不一定介意这个解决方案。但是,有没有办法稍微清理一下?我想改变两件事:1. 捕获/抑制 AssertError(很容易做到但看起来很奇怪) 2. 使用 assertDictEqual 而不必继承 TestCase

标签: python


【解决方案1】:

改编自cpython源码:

https://github.com/python/cpython/blob/01fd68752e2d2d0a5f90ae8944ca35df0a5ddeaa/Lib/unittest/case.py#L1091

import difflib
import pprint

def compare_dicts(d1, d2):
    return ('\n' + '\n'.join(difflib.ndiff(
                   pprint.pformat(d1).splitlines(),
                   pprint.pformat(d2).splitlines())))

【讨论】:

    【解决方案2】:

    你可以使用 difflib,但使用 unittest 方法似乎更适合我。但是如果你想使用 difflib.假设以下是两个字典。

    In [50]: dict1
    Out[50]: {1: True, 2: False}
    
    In [51]: dict2
    Out[51]: {1: False, 2: True}
    

    您可能需要将它们转换为字符串(或字符串列表),然后将 difflib 用作正常业务。

    In [43]: a = '\n'.join(['%s:%s' % (key, value) for (key, value) in sorted(dict1.items())])
    In [44]: b = '\n'.join(['%s:%s' % (key, value) for (key, value) in sorted(dict2.items())])
    In [45]: print a
    1:True
    2:False
    In [46]: print b
    1:False
    2:True
    In [47]: for diffs in difflib.unified_diff(a.splitlines(), b.splitlines(), fromfile='dict1', tofile='dict2'):
        print diffs
    

    输出将是:

    --- dict1
    
    +++ dict2
    
    @@ -1,2 +1,2 @@
    
    -1:True
    -2:False
    +1:False
    +2:True
    

    【讨论】:

    • 这看起来很酷。好主意。为什么说unittest方法在这里更合适呢?
    • @durden2.0 unittest 方法似乎提供了一种更简单的方法。无需翻译成字符串等。
    【解决方案3】:

    您可以将.items() 与集合一起使用来执行以下操作:

    >>> d = dict((i,i) for i in range(10))
    >>> d2 = dict((i,i) for i in range(1,11))
    >>>
    >>> set(d.items()) - set(d2.items())
    set([(0, 0)])
    >>>
    >>> set(d2.items()) - set(d.items())
    set([(10, 10)])
    >>>
    >>> set(d2.items()) ^ set(d.items())  #symmetric difference
    set([(0, 0), (10, 10)])
    >>> set(d2.items()).symmetric_difference(d.items())  #only need to actually create 1 set
    set([(0, 0), (10, 10)])
    

    【讨论】:

      【解决方案4】:

      我找到了一个名为datadiff 的库(文档不太清楚),它给出了python 中可散列数据结构的差异。您可以使用 pip 或 easy_install 安装它。试试看!

      【讨论】:

        【解决方案5】:

        Python recipe to create difference (as dictionary) of two dictionaries。您能否描述一下输出应该是什么样子(请附上示例)?

        【讨论】:

        • 我并没有真正设置打印格式。我想看起来像标准 unidiff 的东西会很好。但是,assertDiffEqual() 的打印效果还不错。下面是一些例子:AssertionError: {'a': 'a'} != {'a': 'abc'} - {'a': 'a'} + {'a': 'abc'} ? ++ AssertionError: {'a': 1} != {'a': 2} - {'a': 1} ? ^ + {'a': 2} ? ^
        【解决方案6】:

        使用@mgilson's solution 并更进一步,让OP 请求使用unittest 模块。

        def test_dict_diff(self):
            dict_diff = list(set(self.dict_A.items()).symmetric_difference(set(self.dict_B.items()))))
            fail_message = "too many differences:\nThe differences:\n" +
                           "%s" % "\n".join(dict_diff)
            self.assertTrue((len(dict_diff) < self.maxDiff), fail_message)
        

        【讨论】:

        • 这很简洁,但我认为如果代码已经在使用unittest 模块,则使用内置的assertDictEqual() 是一个更好的解决方案。
        • assertDictEqual 在 2.7+ 我使用 2.6 ...所以我假设每个人都这样做。 :P 但是是的,这样会更好用。
        【解决方案7】:

        查看https://github.com/inveniosoftware/dictdiffer

        print list(diff(
            {2014: [
                dict(month=6, category=None, sum=672.00),
                dict(month=6, category=1, sum=-8954.00),
                dict(month=7, category=None, sum=7475.17),
                dict(month=7, category=1, sum=-11745.00),
                dict(month=8, category=None, sum=-12140.00),
                dict(month=8, category=1, sum=-11812.00),
                dict(month=9, category=None, sum=-31719.41),
                dict(month=9, category=1, sum=-11663.00),
            ]},
        
            {2014: [
               dict(month=6, category=None, sum=672.00),
               dict(month=6, category=1, sum=-8954.00),
               dict(month=7, category=None, sum=7475.17),
               dict(month=7, category=1, sum=-11745.00),
               dict(month=8, category=None, sum=-12141.00),
               dict(month=8, category=1, sum=-11812.00),
               dict(month=9, category=None, sum=-31719.41),
               dict(month=9, category=1, sum=-11663.00),
            ]}))
        

        给出了我认为非常棒的输出:

        [('change', ['2014', 4, 'sum'], (-12140.0, -12141.0))]
        

        即它给出了发生的情况:一个值“改变”,路径“['2014', 4, 'sum']”,它从 -12140.0 变为 -12141.0。

        【讨论】:

          猜你喜欢
          • 2019-08-03
          • 1970-01-01
          • 1970-01-01
          • 2021-05-28
          • 2020-11-10
          • 2015-07-05
          • 2017-11-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多