在运算符中,float("NaN")和np.nan

Ily*_*rov 27 python containers numpy nan

我以前认为inPython 中的运算符使用相等性检查来检查某些集合中元素的存在==,因此element in some_list大致相当于any(x == element for x in some_list).例如:

True in [1, 2, 3]
# True because True == 1
Run Code Online (Sandbox Code Playgroud)

要么

1 in [1., 2., 3.]
# also True because 1 == 1.
Run Code Online (Sandbox Code Playgroud)

然而,众所周知,它NaN本身并不等同.所以我期待的float("NaN") in [float("NaN")]False.而且它False确实是.

但是,如果我们使用numpy.nan而不是float("NaN"),情况则完全不同:

import numpy as np
np.nan in [np.nan, 1, 2]
# True
Run Code Online (Sandbox Code Playgroud)

np.nan == np.nan仍然给False!

这怎么可能?np.nan和之间有什么区别float("NaN")?怎么in处理np.nan

Ale*_*ley 29

要检查产品列表中,巨蟒为测试对象标识第一,然后争取平等的测试仅如果对象是不同的.1

float("NaN") in [float("NaN")]是错误的,因为 比较中涉及两个不同的 NaN对象.因此,对于身份的测试返回False,然后对于相等性的测试也返回False NaN != NaN.

np.nan in [np.nan, 1, 2]但是为True,因为比较中涉及相同的 NaN对象.对象标识的测试返回True,因此Python立即将项目识别为列表中的项目.

许多Python的其他内置Container类型(如元组和集合)的__contains__方法(使用调用in)是使用相同的检查实现的.


1至少在CPython中也是如此.这里的对象标识意味着在相同的内存地址处找到对象:执行列表contains方法,使用PyObject_RichCompareBool方法在可能更复杂的对象比较之前快速比较对象指针.其他Python实现可能有所不同.

  • Yupp.`nan = float("NaN"); [nan]中的nan给出了"真".谢谢! (2认同)
  • @ayhan - 检查身份是一个相对便宜的操作(只是比较内存地址).检查相等性可能是任意昂贵的. (2认同)
  • @John我的一位教授曾经说过,如果它不必是正确的,我可以任意快速地做出来.[文档](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations)对于`s in s`表示:如果s的项等于x,则为True,否则为返回FALSE.看起来像一个错误 - 文档或实现是否有争议.考虑到后果,它应该只是记录`in`操作符实际上做了什么. (2认同)

Pau*_*zer 5

值得一提的是,numpy数组的行为符合预期:

a = np.array((np.nan,))
a[0] in a
# False
Run Code Online (Sandbox Code Playgroud)

主题的变化:

[np.nan]==[np.nan]
# True
[float('nan')]==[float('nan')]
# False
{np.nan: 0}[np.nan]
# 0
{float('nan'): 0}[float('nan')]
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# KeyError: nan
Run Code Online (Sandbox Code Playgroud)

@ AlexRiley的优秀答案涵盖了其他所有内容.

  • 正如我所说,我认为这是一个错误.当arr == item被评估时(item为[5]),那么[5]被广播到类似(概念上)[5,5,5]的东西,所以列表中的列表将在翻译中丢失.我在numpy跟踪器上打开了一个问题. (2认同)