检查python字典是否相等,以允许浮点数有微小差异

时间:2019-05-08 17:54:37

标签: python pytest

对于没有浮点数的字典,我们使用简单的a == b,其中ab是python字典。直到我们最终得到ab在其中某处包含浮点数的情况下,此方法才有效。它们是嵌套的字典,所以我认为这给pytest.approx带来了麻烦。

我们想要的东西会告诉我们这两个字典相等(或近似相等,但是只有在浮点近似的情况下才会失败):

{"foo": {"bar": 0.30000001}} == {"foo": {"bar": 0.30000002}}

pytest.approx()几乎是我想要的 ,但是它不支持嵌套字典。有什么可以做我想要的东西吗?

3 个答案:

答案 0 :(得分:2)

您可以定义自己的近似帮助程序,并支持嵌套字典。不幸的是,pytest不支持使用自定义比较器对approx进行增强,因此您必须编写自己的函数。但是,它并不太复杂:

import pytest
from _pytest.compat import Mapping
from _pytest.python_api import ApproxMapping


def my_approx(expected, rel=None, abs=None, nan_ok=False):
    if isinstance(expected, Mapping):
        return ApproxNestedMapping(expected, rel, abs, nan_ok)
    return pytest.approx(expected, rel, abs, nan_ok)


class ApproxNestedMapping(ApproxMapping):
    def _yield_comparisons(self, actual):
        for k in self.expected.keys():
            if isinstance(actual[k], type(self.expected)):
                gen = ApproxNestedMapping(
                    self.expected[k], rel=self.rel, abs=self.abs, nan_ok=self.nan_ok
                )._yield_comparisons(actual[k])
                for el in gen:
                    yield el
            else:
                yield actual[k], self.expected[k]

    def _check_type(self):
        for key, value in self.expected.items():
            if not isinstance(value, type(self.expected)):
                super()._check_type()

现在使用my_approx代替pytest.approx

def test_nested():
    assert {'foo': {'bar': 0.30000001}} == my_approx({'foo': {'bar': 0.30000002}})

答案 1 :(得分:1)

您可以做的是将字典中的值分离出来,然后检查两个值之间的差的绝对值是否小于使它“足够接近”的值。我从here找到了函数,这是我解开嵌套字典的常用函数。

epislon = 5 

def extract_nested_values(it):
    if isinstance(it, list):
        for sub_it in it:
            yield from extract_nested_values(sub_it)
    elif isinstance(it, dict):
        for value in it.values():
            yield from extract_nested_values(value)
    else:
        yield it


d = {"foo": {"bar": 0.30000001}}
#[0.30000001]
e = {"foo": {"bar": 0.30000002}}
#[0.30000002]

d_value = list(extract_nested_values(d))
e_value = list(extract_nested_values(e))

if set(d.keys()) == set(e.keys()) and abs(e_value[0] - d_value[0]) < epislon:
    print('Close Enough')
else:
    print("not the same")

输出:

Close Enough

答案 2 :(得分:0)

您是否考虑过复制字典(以免影响原始值)iterating through every val,并用round()将每个浮点数舍入?

math.isclose()也比较浮点数,但是我不知道有哪个比较嵌套字典中的所有浮点数。