NaNs是词典的关键

ham*_*ogu 19 python numpy nan

任何人都可以向我解释以下行为吗?

>>> import numpy as np
>>> {np.nan: 5}[np.nan]
5
>>> {float64(np.nan): 5}[float64(np.nan)]
KeyError: nan
Run Code Online (Sandbox Code Playgroud)

为什么它在第一种情况下起作用,而在第二种情况下不起作用?另外,我发现以下的DOES有效:

>>> a ={a: 5}[a]
float64(np.nan)
Run Code Online (Sandbox Code Playgroud)

Sve*_*ach 33

这里的问题是NaN不等于自身,如IEEE标准中对浮点数的定义:

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

当字典查找键时,它大致是这样的:

  1. 计算要查找的键的哈希值.

  2. 对于具有相同散列的dict中的每个键,检查它是否与要查找的键匹配.这项检查包括

    一个.检查对象标识:如果字典中的密钥和要查找is的密钥与操作员指示的对象相同,则找到密钥.

    湾 如果第一次检查失败,请使用__eq__操作员检查是否相等.

第一个例子成功,因为np.nan并且np.nan是同一个对象,所以它们没有比较相等并不重要:

>>> numpy.nan is numpy.nan
True
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,np.float64(np.nan)并且np.float64(np.nan)不是同一个对象 - 两个构造函数调用创建两个不同的对象:

>>> numpy.float64(numpy.nan) is numpy.float64(numpy.nan)
False
Run Code Online (Sandbox Code Playgroud)

由于对象也不比较相等,因此字典会断定找不到密钥并抛出一个KeyError.

你甚至可以这样做:

>>> a = float("nan")
>>> b = float("nan")
>>> {a: 1, b: 2}
{nan: 1, nan: 2}
Run Code Online (Sandbox Code Playgroud)

总之,将NaN作为字典键避免使用似乎更为明智.

  • 最后的声明值得更加重视. (3认同)