是什么让 NaN 能够与 Python 列表包含运算符一起使用?

Sil*_*olo 5 python equality nan

几乎所有使用 IEEE 浮点值的人都曾在某些时候遇到过 NaN(即“不是数字”)。众所周知,NaN 不等于其自身

>>> x = float('nan')
>>> x == x
False
Run Code Online (Sandbox Code Playgroud)

现在,我已经接受了这一点,但我却很难理解一种奇怪的行为。即,

>>> x in [x]
True
Run Code Online (Sandbox Code Playgroud)

我一直以为是list.__contains__这样写的

def __contains__(self, element):
    for x in self:
        if element == x:
            return True
    return False
Run Code Online (Sandbox Code Playgroud)

即,它__eq__在内部使用相关数据类型。确实如此。__eq__如果我使用自己设计的方法定义自定义类,那么我可以验证 Python__eq__在执行包含检查时确实进行了调用。但是,怎么可能存在一个x既为x == x假又为x in [x]真的值(在我们的例子中为 NaN)呢?

__eq__我们也可以通过习俗观察到相同的行为。

class Example:

    def __eq__(self, other):
        return False

x = Example()
print(x == x)   # False
print(x in [x]) # True
Run Code Online (Sandbox Code Playgroud)

Sel*_*cuk 5

根据文档,它首先使用is运算符来检查是否相等,并且由于x is xis Truex in [x]is is is True

对于列表、元组、集合、frozenset、dict 或 collections.deque 等容器类型,表达式x in y等效于any(x is e or x == e for e in y)

请注意,恒等 ( is) 与等式 ( ) 不同==。另请注意,并非所有 NaN 值都由同一对象表示,因此如果您尝试使用两个不同的 NaN 对象进行测试:

>>> float('nan') in [float('nan')]
False
Run Code Online (Sandbox Code Playgroud)

你会看到不同的结果。