I used to believe that in
operator in Python checks the presence of element in some collection using equality checking ==
, so element in some_list
is roughly equivalent to any(x == element for x in some_list)
. For example:
True in [1, 2, 3] # True because True == 1
or
1 in [1., 2., 3.] # also True because 1 == 1.
However, it is well-known that NaN
is not equal to itself. So I expected that float("NaN") in [float("NaN")]
is False
. And it is False
indeed.
However, if we use numpy.nan
instead of float("NaN")
, the situation is quite different:
import numpy as np np.nan in [np.nan, 1, 2] # True
But np.nan == np.nan
still gives False
!
How is it possible? What's the difference between np.nan
and float("NaN")
? How does in
deal with np.nan
?
The np. nan is the IEEE 754 floating-point representation of Not a Number. The nan stands for “not a number“, and its primary constant is to act as a placeholder for any missing numerical values in the array. The nan values are constants defined in numpy: nan, inf.
NaN stands for Not A Number and is one of the common ways to represent the missing value in the data. It is a special floating-point value and cannot be converted to any other type than float. NaN value is one of the major problems in Data Analysis.
nan is a single object that always has the same id, no matter which variable you assign it to. np. nan is np. nan is True and one is two is also True .
In Python, the float type has nan . nan stands for "not a number" and is defined by the IEEE 754 floating-point standard.
To check if the item is in the list, Python tests for object identity first, and then tests for equality only if the objects are different.1
float("NaN") in [float("NaN")]
is False because two different NaN
objects are involved in the comparison. The test for identity therefore returns False, and then the test for equality also returns False since NaN != NaN
.
np.nan in [np.nan, 1, 2]
however is True because the same NaN
object is involved in the comparison. The test for object identity returns True and so Python immediately recognises the item as being in the list.
The __contains__
method (invoked using in
) for many of Python's other builtin Container types, such as tuples and sets, is implemented using the same check.
1 At least this is true in CPython. Object identity here means that the objects are found at the same memory address: the contains method for lists is performed using PyObject_RichCompareBool
which quickly compares object pointers before a potentially more complicated object comparison. Other Python implementations may differ.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With