pytest.approx如何实现其魔力?

时间:2019-05-14 03:26:18

标签: python pytest

pytest approx函数看起来非常酷,就像他们在documentation中所说的那样,它使用了非常直观的语法:

>>> from pytest import approx
>>> 0.1 + 0.2 == approx(0.3)
True
>>> 1 + 1e-8 == approx(1)
True

但这实际上是如何工作的??在第一个示例中,假设左侧减少为0.29999...之类的东西,那么如何在右侧得到与之相等的东西呢? approx函数是否以某种方式知道如何查看==运算符的左值? approx实际上有效的事实看来像是纯巫术,有人可以解释它如何完成其​​巧妙的小技巧吗?

2 个答案:

答案 0 :(得分:2)

这是进入自定义__eq__的标准数据模型挂钩。

下面的简化示例应为您阐明“法术”。

>>> class MyObj: 
...     def __eq__(self, other): 
...         print(self, "is being compared with", other) 
...         return "potato" 
...
>>> obj = MyObj()   
>>> 0.1 + 0.2 == obj
<__main__.MyObj object at 0xcafef00d> is being compared with 0.30000000000000004
'potato'

请注意,float.__eq__将首先尝试处理此比较。上面显示的行为以及approx(0.3)的行为都非常依赖float已明确“退出”与MyObj实例进行比较的事实。它通过返回一个特殊值NotImplemented来做到这一点:

>>> (0.1+0.2).__eq__(obj)
NotImplemented

有关实际的pytest实现,请查看python_api.py::ApproxScalar

答案 1 :(得分:1)

从源代码中,我可以发现它们创建了相应的类的近似版本。例如,它们具有ApproxDecimalApproxScalarApproxMapping等。近似函数会检查您传递的值的类型,然后为其分配一个他们定义的对应的近似类。

因此,当您输入:

0.1 + 0.2 == approx(0.3)

大约将其更改为:

0.1 + 0.2 == ApproxDecimal(0.3)

现在,这些Approx类实现了相应的__eq__()__repr__()函数,可帮助python执行比较。因此,他们能够在这些近似类中定义用于近似匹配的逻辑。