为什么在numpy中,`nan == nan`的结果是False,而`nan in [nan]`的结果是True?

62

虽然问题的第一部分(标题中的部分)之前已经被回答过几次了(即NaN为什么不等于NaN?),但我不明白第二个部分为什么会按照它的方式工作(受到这个问题的启发:如何检查包含NaN的列表)?

也就是说:

>> nan == nan
False

>> nan in [nan]
True

@DSM的回答后面解释问题的附录。那么,为什么float("nan")的行为与nan不同? 它不应该再次评估为简单的nan,为什么解释器会以这种方式运作?

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

基本上,它在第一种情况下指的是相同的泛型 nan,但在第二种情况下创建了一个单独的对象:

>> 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]

2
关于你的补充,float('nan') 总是会创建一个新的对象。你正在测试的 nan 是一个现有的对象,它永远不会与新创建的对象具有相同的 ID。在 Python 中的赋值始终只是引用原始对象;无论 b 是什么,a = b; a is b 总是会返回 True - Mark Ransom
1个回答

58

nan 不等于 nannan 的定义的一部分,所以这个部分很容易理解。

至于 nan in [nan] 为什么为 True,那是因为在列表中判断包含关系时,先测试对象的身份标识再测试相等性。你正在比较同一个对象。

如果你用两个不同的 nan 尝试同样的操作,结果会是 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

您的补充内容与nan实际上并没有多少关系,这就是Python的工作原理。一旦您了解到float("nan")无需返回某个nan单例对象,并且y = x不会复制x而是将名称y绑定到x所指向的对象,那么就没有什么需要理解的了。



嗯...为什么第一个例子中的nan是相同的?为什么它们没有被初始化为两个不同的对象?因为x = nannan in [x]仍然返回True - sashkello
3
你提到的第一个例子是什么?你指的是nan == nan吗?nan指的是一个特定的对象(在这种情况下,我非常确定它是np.nan)。无论你多少次地提到这个名字,它仍然指向同一个对象:没有任何初始化操作。同样,x = nan并不会复制nan,它只是将x作为一个新的名称,并将其命名为也被nan命名的对象。例如,在执行这个操作之后,可以尝试使用x is nan来进行检查。 - DSM
我不明白这与float("nan")有什么不同?nan有不同的“口味”吗?否则,据我所知,float("nan")应该仍然返回nan,这又是同一个对象,不是吗?我想知道为什么nan in [nan]nan in [float("nan")]不同?解释器如何知道列表中的nan是以不同的方式获得的?在这种情况下,我也不明白为什么float("nan")在[float("nan")]中是false... - sashkello
4
不,如我在原问题中所说,nan不是唯一的对象。看上面的记录:两个 nan 具有不同的 id,而且 nans[0] is nans[1] 是 False。nan in [nan] 为 True,因为它基本上是 any(x is nan or x == nan for x in [nan])x is nan 是 True,因此 x == nan 是 False 并不重要。相同的规则适用于 nan in [float("nan")],结果是 x is nan 是 False(它们是不同的对象),而 x == nan 仍然是 False。float("nan") in [float("nan")] 返回 False,因为它们是两个单独的 NaN。 - DSM
1
@sashkello,虽然这并不重要,但确实存在不同类型的NaN,还有信号NaN,其行为相同。 - seberg
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接