首页 > 解决方案 > 检查python字典是否相等,允许浮点数有小的差异

问题描述

对于没有浮点数的字典,我们使用简单的a == bwhereabare python 字典。这很有效,直到我们最终在其中的某个地方包含ab包含浮点数。它们是嵌套字典,所以我认为这会带来pytest.approx麻烦。

我们想要的是告诉我们这两个字典相等(或近似相等,但不会仅在浮点近似上失败)的东西:

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

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

标签: pythonpytest

解决方案


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

import pytest
from collections.abc 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}})

推荐阅读