You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python 3.6字典中含NaN元组的可哈希对象异常行为问询

关于Python字典+NaN的“意外行为”解释

首先咱们把场景还原清楚——你创建了一个生成含三个NaN的元组的lambda:

null_generator = lambda: (float('nan'), float('nan'), float('nan'))

然后发现两次调用这个lambda得到的不同元组对象,在结合Pandas使用时表现出了不符合直觉的行为,对吧?

核心原因:NaN的特殊特性

这其实不是字典的bug,而是float('nan')本身的IEEE 754标准特性导致的,结合Python和Pandas的不同处理逻辑,就出现了“意外”:

  • NaN的相等性:根据标准,NaN != NaN——你可以直接在终端测试:
    >>> float('nan') == float('nan')
    False
    
  • NaN的哈希值:但在CPython中,hash(float('nan'))会返回一个固定值(比如3.6版本里是0),也就是说所有NaN的哈希值都是相同的:
    >>> hash(float('nan')) == hash(float('nan'))
    True
    

原生Python字典的表现

对于原生Python字典来说,判断两个键是否“相同”需要满足两个条件:哈希值相等,且两个对象用==比较返回True。

所以如果你把两次生成的含NaN的元组作为键:

a = null_generator()
b = null_generator()
d = {}
d[a] = "first"
d[b] = "second"
print(d)

你会得到一个包含两个键的字典,因为a == b返回False(逐元素比较都是NaN,而NaN不等于自己),哪怕它们的哈希值相同。

Pandas中的特殊处理

但你是在使用Pandas时发现的问题,这就涉及到Pandas对NaN的特殊逻辑了:
Pandas为了方便数据处理,刻意将NaN视为相等的索引/键。比如当你用含NaN的元组作为pd.Index或者pd.Series的索引时,Pandas会把它们当成同一个索引项,这和原生Python字典的行为不一样。

举个例子:

import pandas as pd
s = pd.Series([1, 2], index=[null_generator(), null_generator()])
print(s)

你会发现最终的Series只有一个索引项,第二个值覆盖了第一个,因为Pandas把这两个含NaN的元组视为相同的索引。

怎么避免这个问题?

如果你需要在Pandas中区分这些含NaN的元组,可以考虑:

  • 用其他标识代替NaN,比如自定义一个特殊对象(比如class NullMarker: pass,然后用NullMarker()代替float('nan')),这样每个对象都是唯一的,哈希值和相等性都符合直觉。
  • 如果必须用NaN,可以额外添加一个唯一标识字段,把元组扩展成(nan, nan, nan, unique_id),这样即使前三个元素是NaN,第四个唯一ID也能让它们成为不同的键/索引。

内容的提问来源于stack exchange,提问作者Nikhil Shinday

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:06:05