简体   繁体   中英

How does pytest.approx accomplish its magic?

The pytest approx function seems really, cool, and as they say in their documentation it uses a really intuitive syntax:

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

But how does this actually work ? In the first example, let's say the left side reduces to something like 0.29999... , so how can I have something on the right side that evaluates to being equal to it? Does the approx function somehow know how to look at the lvalue of the == operator? The fact that approx actually works seems like pure sorcery, can someone explain how it accomplishes its neat little trick?

This is a standard datamodel hook into a custom __eq__ .

The simplified example below should clarify the "sorcery" for you.

>>> 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'

Note that float.__eq__ will get the first attempt at handling this comparison. The behavior shown above, and also for approx(0.3) , crucially relies on the fact that float has explicitly "opted out" of comparing with MyObj instances. It does this by returning a special value NotImplemented :

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

For the actual pytest implementation, look in python_api.py::ApproxScalar .

From the source code I could find that they create corresponding Approx version of the classes. For example, they have ApproxDecimal , ApproxScalar , ApproxMapping and so on. The approx function checks the type of the value you pass and then assigns it a corresponding approximate class that they have defined.

So when you enter:

0.1 + 0.2 == approx(0.3)

the approx changes it to:

0.1 + 0.2 == ApproxDecimal(0.3)

Now these Approx classes implement corresponding __eq__() and __repr__() functions that help python perform the comparison. Hence they are able to define the logic for approximate matching within these Approximate classes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM