我在比较两个相似的词典时遇到了一些麻烦。我想更严格地比较值(可能还有键)。
这是真正基本的问题:
>>> {'a': True} == {'a': 1}
True
同样(并且有些令人困惑):
>>> {1: 'a'} == {True: 'a'}
True
这是有道理的,因为True == 1
。我正在寻找的东西更像is
,但比较两个可能嵌套的词典。显然你不能在两个字典上使用is
,因为即使所有元素都相同,它也总会返回False
。
我目前的解决方案是使用json.dumps
来获取两者的字符串表示并进行比较。
>>> json.dumps({'a': True}, sort_keys=True) == json.dumps({'a': 1}, sort_keys=True)
False
但这只适用于所有内容都是JSON可序列化的。
我还尝试手动比较所有键和值:
>>> l = {'a': True}
>>> r = {'a': 1}
>>> r.keys() == l.keys() and all(l[key] is r[key] for key in l.keys())
False
但如果字典有一些嵌套结构,则会失败。我想我可以写一个递归版本来处理嵌套的情况,但它似乎不必要的丑陋和非pythonic。
是否有“标准”或简单的方法?
谢谢!
答案 0 :(得分:2)
你非常接近JSON:使用Python的pprint
模块代替。记录这些用于在Python 2.5+和3中对字典进行排序:
在计算显示之前,字典按键排序。
让我们确认一下。这是Python 3.6中的一个会话(即使对于常规dict
对象,它也可以方便地保留插入顺序):
Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a = {2: 'two', 3: 'three', 1: 'one'}
>>> b = {3: 'three', 2: 'two', 1: 'one'}
>>> a
{2: 'two', 3: 'three', 1: 'one'}
>>> b
{3: 'three', 2: 'two', 1: 'one'}
>>> a == b
True
>>> c = {2: 'two', True: 'one', 3: 'three'}
>>> c
{2: 'two', True: 'one', 3: 'three'}
>>> a == b == c
True
>>> from pprint import pformat
>>> pformat(a)
"{1: 'one', 2: 'two', 3: 'three'}"
>>> pformat(b)
"{1: 'one', 2: 'two', 3: 'three'}"
>>> pformat(c)
"{True: 'one', 2: 'two', 3: 'three'}"
>>> pformat(a) == pformat(b)
True
>>> pformat(a) == pformat(c)
False
>>>
让我们快速确认漂亮打印对嵌套词典进行排序:
>>> a['b'] = b
>>> a
{2: 'two', 3: 'three', 1: 'one', 'b': {3: 'three', 2: 'two', 1: 'one'}}
>>> pformat(a)
"{1: 'one', 2: 'two', 3: 'three', 'b': {1: 'one', 2: 'two', 3: 'three'}}"
>>>
因此,不是序列化为JSON,而是使用pprint.pformat()
进行序列化。我想可能会有一些角落情况,你想要考虑的两个对象不相等,但仍会创建相同的漂亮打印表示。但这些情况应该是罕见的,你想要一些简单的Pythonic,这就是。
答案 1 :(得分:0)
您可以使用isinstance()在常规字典条目和嵌套字典条目之间进行描述。通过这种方式,您可以使用is
进行迭代以进行严格比较,还可以检查何时需要将某个级别下载到嵌套字典中。
https://docs.python.org/3/library/functions.html#isinstance
myDict = {'a': True, 'b': False, 'c': {'a': True}}
for key, value in myDict.items():
if isinstance(value, dict):
# do what you need to do....
else:
# etc...
答案 2 :(得分:0)
您可以逐个元素地测试所有(键,值)对的标识:
def equal_dict(d1, d2):
return all((k1 is k2) and (v1 is v2)
for (k1, v1), (k2, v2) in zip(d1.items(), d2.items()))
>>> equal_dict({True: 'a'}, {True: 'a'})
True
>>> equal_dict({1: 'a'}, {True: 'a'})
False
这适用于float
,int
,str
和bool
,但不适用于其他序列或更复杂的对象。
无论如何,如果你需要,这是一个开始。
答案 3 :(得分:0)
我认为你正在寻找这样的东西。但是,由于您没有提供示例数据,我不会猜测它可能是什么
from boltons.itertools import remap
def compare(A, B): return A == B and type(A) == type(B)
dict_to_compare_against = { some dict }
def visit(path, key, value):
cur = dict_to_compare_against
for i in path:
cur = cur[i]
if not compare(cur, value):
raise Exception("Not equal")
remap(other_dict, visit=visit)