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

Python中直接比较字典与转集合比较的差异及异常排查

字典直接比较 vs 转集合比较的区别,以及你的单元测试问题解析

一、直接用==比较字典 vs 转集合后比较的核心差异

这两种方式的逻辑完全不一样,我给你拆解清楚:

  • 字典==比较的是「完整的键值对匹配」
    当你用dict1 == dict2时,Python会做这几件事:

    1. 检查两个字典的键是否完全一致(数量、内容都得一模一样)
    2. 对每个键,检查对应的值是否相等(包括嵌套结构,比如字典里的字典、列表都会递归比较)
    3. 划重点:从Python 3.7开始,字典是插入有序的,但==比较完全不关心键的顺序——只要所有键值对都匹配,哪怕顺序天差地别,结果都是True
  • 转集合比较的是「键值对的存在性」
    当你把字典转成集合(比如set(dict.items())),你其实是把每个键值对转成了(key, value)元组,然后用集合来比较。集合的特性是无序、去重,所以它只关心两个集合里的元素(也就是键值对元组)是否完全相同,不关心顺序。但要注意:如果你的字典里有不可哈希的值(比如列表、自定义字典这类无法被哈希的类型),这种方式根本用不了,会直接抛出TypeError。

二、你的单元测试问题:字典==False,转集合后True

结合你的场景(网站接口数据 vs Postman保存的本地数据),我猜大概率是下面两种情况之一:

情况1:字典里包含NaN值

这是最常见的原因!因为在Python中,float('nan')(非数字)有个特殊性质:它不等于任何值,包括它自己。比如:

>>> float('nan') == float('nan')
False

所以如果你的两个字典里,某个键对应的值都是NaN,那么字典==比较时,这个键值对会被判定为不相等,导致整个比较返回False。

但当你把键值对转成集合时,Python对NaN的哈希值做了特殊处理:所有NaN的哈希值都是相同的。所以集合会认为(key, nan)这个元组是同一个元素,因此集合比较会返回True。

举个例子验证:

dict_from_api = {"id": 123, "score": float('nan')}
dict_from_postman = {"score": float('nan'), "id": 123}

print(dict_from_api == dict_from_postman)  # False
print(set(dict_from_api.items()) == set(dict_from_postman.items()))  # True

情况2:你使用了自定义字典类,重写了__eq__方法

如果网站返回的字典不是Python原生的dict,而是某个库自定义的字典子类,并且这个子类错误地重写了__eq__方法,把键的顺序也纳入了比较逻辑(比如直接比较list(dict.items())),那么就会出现「键值对完全相同但顺序不同时,==返回False」的情况。而转成集合后,因为集合不关心顺序,所以会返回True。

比如这个自定义字典的例子:

class OrderedDictThatCaresAboutOrder(dict):
    def __eq__(self, other):
        # 错误地比较了键值对的顺序
        return list(self.items()) == list(other.items())

dict1 = OrderedDictThatCaresAboutOrder({"a":1, "b":2})
dict2 = OrderedDictThatCaresAboutOrder({"b":2, "a":1})

print(dict1 == dict2)  # False
print(set(dict1.items()) == set(dict2.items()))  # True

怎么解决你的单元测试问题?

如果是NaN的问题,你可以自定义一个比较函数,专门处理NaN的情况:

import math

def dicts_are_equal(d1, d2):
    if d1.keys() != d2.keys():
        return False
    for key in d1:
        val1, val2 = d1[key], d2[key]
        # 处理NaN的情况
        if isinstance(val1, float) and isinstance(val2, float):
            if math.isnan(val1) and math.isnan(val2):
                continue
        # 递归处理嵌套字典
        if isinstance(val1, dict) and isinstance(val2, dict):
            if not dicts_are_equal(val1, val2):
                return False
        elif val1 != val2:
            return False
    return True

如果是自定义字典的问题,你可以把两个字典都转成原生dict再比较:

dict1 = dict(dict_from_api)
dict2 = dict(dict_from_postman)
print(dict1 == dict2)  # 现在会返回True,因为原生dict的==不关心顺序

内容的提问来源于stack exchange,提问作者Albert Rothman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:05:06