[英]Assert that two dictionaries are almost equal
I am trying to assert that two dictionaries are almost equal, but I can't seem to do that.我试图断言两个字典几乎相等,但我似乎无法做到这一点。
Here is an example:下面是一个例子:
>>> 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}
I would like this to pass, like that:我希望这通过,就像这样:
>>> nt.assert_almost_equal(12.4, 5.6 + 6.8)
I am hoping that I missing something simple like, nt.assert_almost_dict_equal
, or maybe there is parameter that I could pass to nt.assert_dict_equal
that specifies how close floating points should be, but I can't find anything.我希望我错过了一些简单的东西, nt.assert_almost_dict_equal
,或者可能有参数可以传递给nt.assert_dict_equal
指定浮点应该有多接近,但我找不到任何东西。
Of course, I could just loop over the dictionaries and use nt.assert_almost_equal
to compare the values individually;当然,我可以循环字典并使用nt.assert_almost_equal
单独比较值; however, in my case the dictionary is more complicated, so I was hoping to avoid that.然而,就我而言,字典更复杂,所以我希望避免这种情况。
What is the best way to assert that two dictionaries are almost equal?断言两个字典几乎相等的最佳方法是什么?
The comment by @dano answered my question: @dano 的评论回答了我的问题:
I copied a function from a link provided by dano我从dano 提供的链接中复制了一个函数
import unittest
import numpy
def assertDeepAlmostEqual(test_case, expected, actual, *args, **kwargs):
"""
Assert that two complex structures have almost equal contents.
Compares lists, dicts and tuples recursively. Checks numeric values
using test_case's :py:meth:`unittest.TestCase.assertAlmostEqual` and
checks all other values with :py:meth:`unittest.TestCase.assertEqual`.
Accepts additional positional and keyword arguments and pass those
intact to assertAlmostEqual() (that's how you specify comparison
precision).
:param test_case: TestCase object on which we can call all of the basic
'assert' methods.
:type test_case: :py:class:`unittest.TestCase` object
"""
is_root = not '__trace' in kwargs
trace = kwargs.pop('__trace', 'ROOT')
try:
if isinstance(expected, (int, float, long, complex)):
test_case.assertAlmostEqual(expected, actual, *args, **kwargs)
elif isinstance(expected, (list, tuple, numpy.ndarray)):
test_case.assertEqual(len(expected), len(actual))
for index in xrange(len(expected)):
v1, v2 = expected[index], actual[index]
assertDeepAlmostEqual(test_case, v1, v2,
__trace=repr(index), *args, **kwargs)
elif isinstance(expected, dict):
test_case.assertEqual(set(expected), set(actual))
for key in expected:
assertDeepAlmostEqual(test_case, expected[key], actual[key],
__trace=repr(key), *args, **kwargs)
else:
test_case.assertEqual(expected, actual)
except AssertionError as exc:
exc.__dict__.setdefault('traces', []).append(trace)
if is_root:
trace = ' -> '.join(reversed(exc.traces))
exc = AssertionError("%s\nTRACE: %s" % (exc.message, trace))
raise exc
# My part, using the function
class TestMyClass(unittest.TestCase):
def test_dicts(self):
assertDeepAlmostEqual(self, {'a' : 12.4}, {'a' : 5.6 + 6.8})
def test_dicts_2(self):
dict_1 = {'a' : {'b' : [12.4, 0.3]}}
dict_2 = {'a' : {'b' : [5.6 + 6.8, 0.1 + 0.2]}}
assertDeepAlmostEqual(self, dict_1, dict_2)
def main():
unittest.main()
if __name__ == "__main__":
main()
Result:结果:
Ran 2 tests in 0.000s
OK
I realize you wouldn't import pandas just to do this but if you happen to be using pandas you can convert the dicts to series and use the assert_series_equal
from pandas.testing
which, by default, has check_exact=False
.我意识到您不会仅仅为了执行此操作而导入熊猫,但是如果您碰巧使用熊猫,您可以将pandas.testing
转换为系列并使用pandas.testing
中的assert_series_equal
,默认情况下,它具有check_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)
I couldn't get Akavall's function to run so made my own.我无法让 Akavall 的功能运行,所以我自己做了。 Is a little too simply but works for my purposes.有点过于简单,但适用于我的目的。 Code to test that function is working written using pytest使用 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
Validate function output using pytest使用 pytest 验证函数输出
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)
Pytest“大约”完成这项工作
In [10]: {'a': 2.000001} == pytest.approx({'a': 2}) Out[10]: True
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.