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)

Asked By: Nineteendo

||

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?

Answered By: sandro

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)
Answered By: wjandrea
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.