Python字典的==问题

1,372 阅读2分钟

今天和大家分享下python3中dict的==运算符

起因:前几天追查线上bug时,看到同事用了“==”比较两个dict是否相等,直觉告诉我这里容易出问题。 我用python3也不是很久,不太确定python是如何比较两个dict,所以针对python中dict的==实现做了下调研,和大家简单分享下。

先说结论: python3中对dict的比较忽略key的顺序,而且是迭代所有层级进行比较的。

写一个简单的测试程序:

src = {"test":{"write": "100", "read": False}, "pipe": 23}
dst = {"pipe": 23, "test":{"write": "100", "read": False}}
print(src == dst) // True

再思考一个问题,如果dict中存在list会是什么情况呢?

我们再写个例子验证下:

src = {"test":[100,200], "pipe": 23}
dst = {"pipe": 23, "test":[100,200]}
print(src == dst) // True

此时结果还是True,那如果list中又放了dict呢? 我们再来验证下

src = {"test":[{"read": False,"write": "100"}], "pipe": 23}
dst = {"pipe": 23, "test":[{"write": "100", "read": False}]}
print(src == dst) // True

此时结果还是True,那如果list中dict的顺序产生差异呢?

src = {"test":[{"read": False},{"write": "100"}], "pipe": 23}
dst = {"pipe": 23, "test":[{"write": "100"},{"read": False}]}
print(src == dst) // False

此时结果就变成了False,根据现象大概推断一下,dict逐层迭代,当value是list的时候,list的比较是有序的。 翻阅了部分python的源码,实现和预想的逻辑基本是一致的。 但是我们此处的业务逻辑,dict中如果存在list时,是要忽略顺序的,只要list中的值相等就认为两个list相等。于是写了一个简单的方法比较两个dict,忽略list的顺序。

def ignore_order_cmp(src={}, dst={}, sort_fun=None):
    """
    比较两个字典或者list是否相等。
    和原始比较方法的不同之处在于,对list类型先做排序,再进行比较。
    params:src dst 需要比较的两组数据
    params:sort_fun list类型做排序时,自定义的排序方法
    """
    if isinstance(src, dict) & isinstance(dst, dict):
        for key in dst:
            if key not in src:
                return False
        for key in src:
            if key in dst:
                if not ignore_order_cmp(src[key], dst[key], sort_fun):
                    return False
            else:
                return False
        return True
    elif isinstance(src, list) & isinstance(dst, list):
        if len(src) != len(dst):
            return False
        else:
            if sort_fun is not None:
                src.sort(key=sort_fun)
                dst.sort(key=sort_fun)
            for i in range(0, len(src)):
                if not ignore_order_cmp(src[i], dst[i], sort_fun):
                    return False
            return True
    else:
        return src == dst

大家在使用==判等时也要注意,phton3对不同数据类型__eq__()方法做了重载,避免踩坑。