62

While the first part of the question (which is in the title) has been answered a few times before (i.e., Why is NaN not equal to NaN?), I don't see why the second piece works the way it does (inspired by this question How to Check list containing NaN)?

Namely:

>> nan == nan
False

>> nan in [nan]
True

An explanatory addendum to the question considering the answer from @DSM. So, why float("nan") is behaving differently from nan? Shouldn't it evaluate again to simple nan and why interpreter behaves this way?

>> x = float("nan")
>> y = nan
>> x
nan
>> y
nan
>> x is nan, x is float("nan"), y is nan
(False, False, True)

Basically, it refers to same generic nan in the first case, but creates separate object in the second:

>> nans = [nan for i in range(2)]
>> map(id, nans)
[190459300, 190459300]
>> nans = [float("nan") for i in range(2)]
>> map(id, nans)
[190459300, 190459301]
Community
  • 1
  • 1
sashkello
  • 17,306
  • 24
  • 81
  • 109
  • 2
    Re your addendum, `float('nan')` always creates a new object. The `nan` that you're testing against is a pre-existing object that will never be the same ID as a newly created one. Assignment in Python always simply references the original object; `a = b; a is b` will always return `True` no matter what `b` is. – Mark Ransom Dec 02 '13 at 04:33

1 Answers1

57

nan not being equal to nan is part of the definition of nan, so that part's easy.

As for nan in [nan] being True, that's because identity is tested before equality for containment in lists. You're comparing the same two objects.

If you tried the same thing with two different nans, you'd get False:

>>> nans = [float("nan") for i in range(2)]
>>> map(id, nans)
[190459300, 190459284]
>>> nans
[nan, nan]
>>> nans[0] is nans[1]
False
>>> nans[0] in nans
True
>>> nans[0] in nans[1:]
False

Your addendum doesn't really have much to do with nan, that's simply how Python works. Once you understand that float("nan") is under no obligation to return some nan singleton, and that y = x doesn't make a copy of x but instead binds the name y to the object named by x, there's nothing left to get.

DSM
  • 342,061
  • 65
  • 592
  • 494
  • Hmm... Why the nan's are the same in the first example? Why aren't they initialized as two different objects? Because `x = nan` and `nan in [x]` still returns `True`. – sashkello Dec 02 '13 at 02:52
  • 3
    @sashkello: what first example are you referring to? Your `nan == nan`? `nan` names a particular object (in this case, I'm pretty sure it was the `np.nan`). No matter how many times you say the name, it still refers to the same object: there's no initialization going on. Similarly, `x = nan` doesn't make a copy of `nan`, it just makes `x` a new name and says that it names the object which is also named by `nan`. Try `x is nan` after doing that, for example. – DSM Dec 02 '13 at 02:55
  • I just don't see how that is different from float("nan") then? Are there different 'flavors' of nan's? Otherwise, as I understand, float("nan") should still return nan which is again one same object, isn't it? I want to understand why `nan in [nan]` is different from `nan in [float("nan")]? How does interpreter know that the nan in the list has been obtained in a different way? I also don't get why float("nan") in [float("nan")] is false in such case... – sashkello Dec 02 '13 at 03:11
  • 4
    No, as I said in the original question, nans aren't unique objects. Look at the above transcript: the two `nan`s have different ids and `nans[0] is nans[1]` is False. `nan in [nan]` is True because it's basically `any(x is nan or x == nan for x in [nan])`. `x is nan` is True so it doesn't matter that `x == nan` is False. The same rule applied to `nan in [float("nan")]` gives `x is nan` is False (they're different objects) and `x == nan` is still False. `float("nan") in [float("nan")]` gives False because they're TWO SEPARATE NANS. – DSM Dec 02 '13 at 03:14
  • OK, got it now. I just was thinking about nan as some sort of object value, while it is really object name... – sashkello Dec 02 '13 at 04:37
  • @sashkello: yep, that's exactly it. – DSM Dec 02 '13 at 04:38
  • 1
    @sashkello, not that it matters much, but yes there actually *are* different flavors of NaNs, there are signalling NaNs too, which behave the same. – seberg Dec 02 '13 at 09:00