Python 断言两本词典几乎相等

Python 断言两本词典几乎相等,python,dictionary,assert,nose,Python,Dictionary,Assert,Nose,我试图断言两本词典几乎相等,但我似乎做不到这一点 以下是一个例子: >>> import nose.tools as nt >>> nt.assert_dict_equal({'a' : 12.4}, {'a' : 5.6 + 6.8}) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/

我试图断言两本词典几乎相等,但我似乎做不到这一点

以下是一个例子:

>>> import nose.tools as nt
>>> nt.assert_dict_equal({'a' : 12.4}, {'a' : 5.6 + 6.8})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/unittest/case.py", line 838, in assertDictEqual
    self.fail(self._formatMessage(msg, standardMsg))
  File "/usr/lib/python2.7/unittest/case.py", line 413, in fail
    raise self.failureException(msg)
AssertionError: {'a': 12.4} != {'a': 12.399999999999999}
- {'a': 12.4}
+ {'a': 12.399999999999999}
我希望我遗漏了一些简单的东西,比如,
nt.assert\u几乎等于
,或者可能有一个参数可以传递给
nt.assert\u dict\u equal
,它指定浮点应该有多近,但我找不到任何东西

当然,我可以在字典上循环使用
nt.assert_几乎等于
来分别比较这些值;然而,就我而言,字典更复杂,所以我希望避免这种情况


断言两本词典几乎相等的最佳方式是什么?

由@dano发表的评论回答了我的问题:

我从一个函数复制了一个函数

结果:

Ran 2 tests in 0.000s

OK

我无法让Akavall的函数运行,所以我自己做了。这有点太简单了,但符合我的目的。使用pytest编写测试该函数是否正常工作的代码

from numbers import Number
from math import isclose

def dictsAlmostEqual(dict1, dict2, rel_tol=1e-8):
    """
    If dictionary value is a number, then check that the numbers are almost equal, otherwise check if values are exactly equal
    Note: does not currently try converting strings to digits and comparing them. Does not care about ordering of keys in dictionaries
    Just returns true or false
    """
    if len(dict1) != len(dict2):
        return False
    # Loop through each item in the first dict and compare it to the second dict
    for key, item in dict1.items():
        # If it is a nested dictionary, need to call the function again
        if isinstance(item, dict):
            # If the nested dictionaries are not almost equal, return False
            if not dictsAlmostEqual(dict1[key], dict2[key], rel_tol=rel_tol):
                return False
        # If it's not a dictionary, then continue comparing
        # Put in else statement or else the nested dictionary will get compared twice and
        # On the second time will check for exactly equal and will fail
        else:
            # If the value is a number, check if they are approximately equal
            if isinstance(item, Number):
                # if not abs(dict1[key] - dict2[key]) <= rel_tol:
                # https://stackoverflow.com/questions/5595425/what-is-the-best-way-to-compare-floats-for-almost-equality-in-python
                if not isclose(dict1[key], dict2[key], rel_tol=rel_tol):
                    return False
            else:
                if not (dict1[key] == dict2[key]):
                    return False
    return True
import pytest
import dictsAlmostEqual
def test_dictsAlmostEqual():
    a = {}
    b = {}
    assert dictsAlmostEqual(a, b)
    a = {"1": "a"}
    b = {}
    assert not dictsAlmostEqual(a, b)
    a = {"1": "a"}
    b = {"1": "a"}
    assert dictsAlmostEqual(a, b)
    a = {"1": "a"}
    b = {"1": "b"}
    assert not dictsAlmostEqual(a, b)
    a = {"1": "1.23"}
    b = {"1": "1.23"}
    assert dictsAlmostEqual(a, b)
    a = {"1": "1.234"}
    b = {"1": "1.23"}
    assert not dictsAlmostEqual(a, b)
    a = {"1": 1.000000000000001, "2": "a"}
    b = {"1": 1.000000000000002, "2": "a"}
    assert not dictsAlmostEqual(a, b, rel_tol=1e-20)
    assert dictsAlmostEqual(a, b, rel_tol=1e-8)
    assert dictsAlmostEqual(a, b)
    # Nested dicts
    a = {"1": {"2": 1.000000000000001}}
    b = {"1": {"2": 1.000000000000002}}
    assert not dictsAlmostEqual(a, b, rel_tol=1e-20)
    assert dictsAlmostEqual(a, b, rel_tol=1e-8)
    assert dictsAlmostEqual(a, b)
    a = {"1": {"2": 1.000000000000001, "3": "a"}, "2": "1.23"}
    b = {"1": {"2": 1.000000000000002, "3": "a"}, "2": "1.23"}
    assert not dictsAlmostEqual(a, b, rel_tol=1e-20)
    assert dictsAlmostEqual(a, b, rel_tol=1e-8)
    assert dictsAlmostEqual(a, b)

我知道你不会仅仅为了这个目的而导入pandas,但是如果你碰巧使用pandas,你可以将dicts转换为series,并使用
pandas.testing
中的
断言\u series\u equal
,默认情况下,它有
check\u exact=False

>>> import pandas as pd
>>> from pandas.testing import assert_series_equal
>>> a = pd.Series({'a' : 12.4})
>>> b = pd.Series({'a': 12.399999999999999})
>>> assert_series_equal(a, b)
Pytest“近似”完成此工作

[10]中的
:{'a':2.000001}==pytest.approx({'a':2})

Out[10]:True

我认为您需要自己迭代并比较这些值
assert_几乎等于
仅为可直接计算差值的数字类型提供。如果您发现需要自己的类型,请查看此处的“assertDeepAlmostEqual:@dano,这很有趣,谢谢。Downvoter,您能解释下一票的原因吗。我相信自我回答很好。你认为我没有给@dano足够的信任吗?这可能是一种糟糕的风格,但是如果你通过'unittest.TestCase.assertDeepAlmostEqual=assertDeepAlmostEqual'来修补测试用例,那么你可以像其他测试一样使用测试,例如
self.assertDeepAlmostEqual(dict_1,dict_2)
还应注意,在我的例子中,我必须对所有嵌套集合进行排序,因此您可以将此处的代码与此代码片段一起使用,而无需使用monkey patch
TestCase
。您可以简单地将其子类化。实际上,
testtools.TestCase
就是这样做的。Python 2不再受支持,因此我将用
range
替换
xrange
。另外,
long
应该是
numpy.long
或者您可以从numpy显式地
导入long,ndarray
并保存导入所有numpy。
import pytest
import dictsAlmostEqual
def test_dictsAlmostEqual():
    a = {}
    b = {}
    assert dictsAlmostEqual(a, b)
    a = {"1": "a"}
    b = {}
    assert not dictsAlmostEqual(a, b)
    a = {"1": "a"}
    b = {"1": "a"}
    assert dictsAlmostEqual(a, b)
    a = {"1": "a"}
    b = {"1": "b"}
    assert not dictsAlmostEqual(a, b)
    a = {"1": "1.23"}
    b = {"1": "1.23"}
    assert dictsAlmostEqual(a, b)
    a = {"1": "1.234"}
    b = {"1": "1.23"}
    assert not dictsAlmostEqual(a, b)
    a = {"1": 1.000000000000001, "2": "a"}
    b = {"1": 1.000000000000002, "2": "a"}
    assert not dictsAlmostEqual(a, b, rel_tol=1e-20)
    assert dictsAlmostEqual(a, b, rel_tol=1e-8)
    assert dictsAlmostEqual(a, b)
    # Nested dicts
    a = {"1": {"2": 1.000000000000001}}
    b = {"1": {"2": 1.000000000000002}}
    assert not dictsAlmostEqual(a, b, rel_tol=1e-20)
    assert dictsAlmostEqual(a, b, rel_tol=1e-8)
    assert dictsAlmostEqual(a, b)
    a = {"1": {"2": 1.000000000000001, "3": "a"}, "2": "1.23"}
    b = {"1": {"2": 1.000000000000002, "3": "a"}, "2": "1.23"}
    assert not dictsAlmostEqual(a, b, rel_tol=1e-20)
    assert dictsAlmostEqual(a, b, rel_tol=1e-8)
    assert dictsAlmostEqual(a, b)
>>> import pandas as pd
>>> from pandas.testing import assert_series_equal
>>> a = pd.Series({'a' : 12.4})
>>> b = pd.Series({'a': 12.399999999999999})
>>> assert_series_equal(a, b)