我曾经相信Python中的in
运算符使用等式检查==
来检查某些集合中元素的存在,因此element in some_list
大致相当于any(x == element for x in some_list)
。例如:
True in [1, 2, 3]
# True because True == 1
或
1 in [1., 2., 3.]
# also True because 1 == 1.
然而,众所周知NaN
不等于它自己。所以我希望float("NaN") in [float("NaN")]
是False
。它确实是False
。
但是,如果我们使用numpy.nan
代替float("NaN")
,则情况就大不相同了:
import numpy as np
np.nan in [np.nan, 1, 2]
# True
但np.nan == np.nan
仍然提供False
!
怎么可能? np.nan
和float("NaN")
之间的区别是什么? in
如何处理np.nan
?
答案 0 :(得分:28)
要检查项目是否在列表中,Python首先测试对象标识 ,然后仅在对象不同时测试相等性。 1
float("NaN") in [float("NaN")]
为False,因为比较中涉及两个不同的 NaN
个对象。因此,对于身份的测试返回False,然后对于相等性的测试也返回False,因为NaN != NaN
。
np.nan in [np.nan, 1, 2]
但是为True,因为比较中涉及相同的 NaN
对象。对象标识的测试返回True,因此Python立即将该项识别为列在列表中。
对于许多Python的其他内置容器类型(例如元组和集合),__contains__
方法(使用in
调用)是使用相同的检查实现的。
1 至少在CPython中也是如此。这里的对象标识意味着在同一个内存地址中找到对象:使用contains method for lists执行PyObject_RichCompareBool
,它可以在可能更复杂的对象比较之前快速比较对象指针。其他Python实现可能有所不同。
答案 1 :(得分:5)
值得一提的是numpy数组的行为符合预期:
a = np.array((np.nan,))
a[0] in a
# False
主题的变化:
[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
@ AlexRiley的优秀答案涵盖了其他所有内容。