Pylint redundant comparison for NaN
Question:
Why does Pylint think this is a redundant comparison? Is this not the fastest way to check for NaN?
Refactor: R0124
Redundant comparison – value_1 != value_1
Redundant comparison – value_2 != value_2
How else am I supposed to check if two values are equal including when they’re nan?
NaN = float("NaN")
def compare(value_1, value_2):
match_nan = value_1 != value_1
print(match_nan and
value_2 != value_2 or
value_1 == value_2)
compare(1, 1)
compare(1, NaN)
compare(NaN, 1)
compare(NaN, NaN)
Output:
True
False
False
True
Now, sure math.is_nan is a better solution if you’re working with custom classes:
from math import isnan
class NotEQ:
def __eq__(self, other):
return False
not_eq = NotEQ()
print(not_eq != not_eq)
print(isnan(not_eq))
Output:
True
... TypeError: must be real number, not NotEQ
I’m writing a JSON patcher, and I don’t think the normal behaviour is very useful when you want to be able to remove them from lists, or raise an error is two values aren’t equal (but allowing NaN and NaN)
Answers:
pylint throws this issue whenever you compare either a constant or a variable with itself. I case of a variable it compares the name (see _check_logical_tautology
in the source). So you could circumvent this by renaming one side of the comparison like this:
def compare(value_1, value_2):
v_1 = value_1
v_2 = value_2
match_nan = v_1 != value_1
print(match_nan and v_2 != value_2 or value_1 == value_2)
at least to get rid of the linting issue. However I would also follow wjandrea’s advice and go for How can I check for NaN values?
Use math.isnan(x)
; it’s just as fast as x != x
. The answer you cited that says x != x
is fastest is using a bad test (and I put a comment there to explain). Here’s a fixed version:
In [1]: %%timeit x = float('nan')
...: x != x
...:
...:
36 ns ± 0.51 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
In [2]: %%timeit x = float('nan'); from math import isnan
...: isnan(x)
...:
...:
35.8 ns ± 0.282 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Why does Pylint think this is a redundant comparison? Is this not the fastest way to check for NaN?
Refactor: R0124
Redundant comparison – value_1 != value_1
Redundant comparison – value_2 != value_2
How else am I supposed to check if two values are equal including when they’re nan?
NaN = float("NaN")
def compare(value_1, value_2):
match_nan = value_1 != value_1
print(match_nan and
value_2 != value_2 or
value_1 == value_2)
compare(1, 1)
compare(1, NaN)
compare(NaN, 1)
compare(NaN, NaN)
Output:
True
False
False
True
Now, sure math.is_nan is a better solution if you’re working with custom classes:
from math import isnan
class NotEQ:
def __eq__(self, other):
return False
not_eq = NotEQ()
print(not_eq != not_eq)
print(isnan(not_eq))
Output:
True
... TypeError: must be real number, not NotEQ
I’m writing a JSON patcher, and I don’t think the normal behaviour is very useful when you want to be able to remove them from lists, or raise an error is two values aren’t equal (but allowing NaN and NaN)
pylint throws this issue whenever you compare either a constant or a variable with itself. I case of a variable it compares the name (see _check_logical_tautology
in the source). So you could circumvent this by renaming one side of the comparison like this:
def compare(value_1, value_2):
v_1 = value_1
v_2 = value_2
match_nan = v_1 != value_1
print(match_nan and v_2 != value_2 or value_1 == value_2)
at least to get rid of the linting issue. However I would also follow wjandrea’s advice and go for How can I check for NaN values?
Use math.isnan(x)
; it’s just as fast as x != x
. The answer you cited that says x != x
is fastest is using a bad test (and I put a comment there to explain). Here’s a fixed version:
In [1]: %%timeit x = float('nan')
...: x != x
...:
...:
36 ns ± 0.51 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
In [2]: %%timeit x = float('nan'); from math import isnan
...: isnan(x)
...:
...:
35.8 ns ± 0.282 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)