Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

type checking for math.isclose()

Basically i got below warning in PyCharm in the statement math.isclose(a_val, b_val)

Expected type 'SupportsFloat', got 'Number' instead

Minimal, reproducible example as below.

from numbers import Number
import math

a_val = '123'
b_val = 123.4

if isinstance(a_val, Number) and isinstance(b_val, Number):
    is_close = math.isclose(a_val, b_val, abs_tol=0.5)

In reality, a_val and b_val are sourced somewhere else which could return float, integer or string. If both a_val and b_val are numeric, I want to check if they are almost equal. Otherwise just ignore it if any of them is string.

Question - what is the best way of type checking before passing a_val and b_val to math.isclose() ? What change should be done to clear the PyCharm wanring?

like image 626
henrywongkk Avatar asked Mar 03 '23 07:03

henrywongkk


2 Answers

math.isclose doesn't support arbitrary Number instances. Like most math functions, math.isclose needs arguments that can be converted to float. A Number could be something like 1+2j, which can't be converted to float. (Also, str doesn't count - it has to be something with a __float__ method.)

I was going to suggest using typing.SupportsFloat, but it looks like I misread the code, and typing.SupportsFloat doesn't support isinstance checks. If your only options are str, float, and int, it's probably simplest to just check for float and int, or to go the other way and just reject str:

if isinstance(a_val, (float, int)) and isinstance(b_val, (float, int)):
    ...

or

if not isinstance(a_val, str) and not isinstance(b_val, str):
    ...
like image 145
user2357112 supports Monica Avatar answered Mar 17 '23 22:03

user2357112 supports Monica


Your solution with checking isinstance(a_val, Number) was close. You just need to change Number to Real from the numbers module. Real numbers support conversion to float so it is the right type to check. And the warning is gone. Full code sample:

from numbers import Real
import math

a_val = '123'
b_val = 123.4

if isinstance(a_val, Real) and isinstance(b_val, Real):
    is_close = math.isclose(a_val, b_val, abs_tol=0.5)
like image 39
sanyassh Avatar answered Mar 17 '23 22:03

sanyassh