Python set() 去重的底层原理:哈希与相等性判断详解

小鹿同学
小鹿同学
发布时间:2026-10-15| 4人浏览过
原创

本文深入解析 Python 中 set() 去重的底层实现机制。集合利用元素的唯一性进行去重,其核心依赖于 __hash__ 和 __eq__ 两个魔术方法的协同工作。当哈希值不同时视为不同元素;哈希值相同时,进一步通过 __eq__ 判断是否真正相等。文章包含自定义类去重的完整代码示例,展示如何重写哈希与相等逻辑以满足特定业务需求。

set是什么?

在数学定义中,集合是由不同元素组成的整体,这些元素被称为集合元素。Python 将这一概念引入到其内置的集合类型对象中。集合对象本质上是一组无序排列且可哈希(hashable)的值。它支持关系测试以及并集、交集等标准集合运算,行为符合数学集合的直观预期。

set特点

集合中的元素具备以下三个核心特征:

1. 确定性:集合中的每一个元素必须是明确且确定的;

2. 互异性:集合内的元素互不相同,例如若集合 A={1, a},则 a 不能等于 1;

3. 无序性:集合中的元素没有顺序之分,例如 {3, 4, 5} 与 {3, 5, 4} 被视为同一个集合。

在 Python 中,集合(set)是一个无序且不包含重复元素的集。它的基本功能包括关系测试和消除重复元素,同时也支持计算交集、差集和并集。与列表(list)类似,但关键区别在于集合不允许包含重复值,且其元素是无序排列的。

在 Python 中,可以使用大括号 {} 来创建集合。需要注意的是,如果要创建或初始化一个空集合,必须使用 set() 函数,而不能使用 {}。因为 {} 在 Python 中被解析为创建一个空的字典,字典这种数据结构将在后续章节中介绍。

一、set去重简单实例

ls = [1,2,3,1,2]
print(set(ls))

对于列表而言,最简单的去重方法是直接调用 set 函数,利用集合元素的唯一性来实现去重。然而,其底层的实现原理究竟如何,往往容易被忽视。

接下来我们将对这一过程进行深入剖析。

二、重新set实现机制


class Foo:
    def __init__(self,name,count):
        self.name = name
        self.count = count
    def __hash__(self):
        print("%s调用了哈希方法"%self.name)
        return hash(id(self))
    def __eq__(self, other):
        print("%s调用了eq方法")
        if self.__dict__ == other.__dict__:
            return True
        else:return False
f1 = Foo('f1',1)
f2 = Foo('f2',2)
f3 = Foo('f3',3)
ls = [f1,f2,f3]
print(set(ls))

从上述简单示例可以看出,set 方法似乎只是调用 hash 方法,然后根据哈希值是否相同来进行去重判断。但事实是否如此简单呢?请看下面的程序分析。


class Foo:
    def __init__(self,name,count):
        self.name = name
        self.count = count
    def __hash__(self):
        print("%s调用了哈希方法"%self.name)
        return hash(self.count)
    def __eq__(self, other):
        print("%s调用了eq方法"%self.name)
        return self.__dict__ == other.__dict__
f1 = Foo('f1',1)
f2 = Foo('f2',1)
f3 = Foo('f3',3)
ls = [f1,f2,f3]
print(set(ls))

观察运行结果可以发现,实际上 f1 和 f3 的哈希值是相等的,但 set 并没有简单地据此判定 f1 和 f3 为重复元素。相反,它会进一步通过 __eq__ 方法判断这两个值是否真正相等,只有当 __eq__ 返回 True 时,才会认为这两个对象实际上是同一个,从而进行去重。为了验证这一说法,我们查看下面的代码示例。

f1 = Foo('f1',1)
f2 = Foo('f1',1)
f3 = Foo('f3',3)
ls = [f1,f2,f3]
print(set(ls))

从输出结果可以看出,去重后的集合中只剩下两个元素,这证实了上述关于哈希冲突处理机制的说法。

三、结论

set 的去重机制是通过 __hash__ 和 __eq__ 两个函数结合实现的: 1. 当两个变量的哈希值不相同时,直接认为这两个变量是不同的; 2. 当两个变量的哈希值相同时(即发生哈希冲突),调用 __eq__ 方法进行比较。若返回值为 True,则认为这两个变量是同一个,应去除其中一个;若返回 False,则不去重,保留两个元素。

四、应用场景需求

假设有一个公司,现有 100 名员工。由于数据库不完善且使用时间较长,数据中存在大量重复记录需要清理。具体需求如下:

每位员工的属性包括:姓名、性别、年龄和部门。由于年龄和部门信息可能会发生变化,因此我们定义:只要两名员工的姓名和性别相同,即视为同一个人。

请根据上述规则实现员工数据的去重:

class Staff:
    def __init__(self,name,gender,age,department):
        self.name = name
        self.gender = gender
        self.age  = age
        self.department = department
    def __hash__(self):
        return hash(self.name+self.gender)
    def __eq__(self, other):
        return True
ls = ['zs','ls','ww','zq']
gender_list = ['man','femal']
staff_list = []
for i in range(100):
    staff_list.append(Staff(ls[i%4],gender_list[i%2],i,'class'))
print(set(staff_list))
print([(i.name,i.gender) for i in set(staff_list)])

到此这篇关于 python set() 去重的底层原理的文章就介绍到这了,更多相关 python set() 去重内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。