当前位置:首页>python>Python 有了 dict ,为啥还要 set ?

Python 有了 dict ,为啥还要 set ?

  • 2026-10-22 17:34:36
Python 有了 dict ,为啥还要 set ?
关注+星标,每天学习Python新技能

来源:网络

字典(dict)不就是“键值对”的集合吗?它能快速查找、去重,功能已经很强大了。那为啥 Python 还要单独搞一个集合(set)出来?这俩是不是有点重复造轮子?学习Python的过程中,一直没有弄清楚明明有Dict对象,为什么还存在Set,直到再次回看课程,才明白个人缘由。这两看似功能重叠的对象背后,是两者核心设计目标的本质差异。今天来聊聊这个问题——搞懂 dict 和 set 的区别,我们写的代码会更简洁、更高效。

先回顾:dict 和 set 的“共同点”

首先得承认,dict 和 set 确实是“近亲”,它们的底层实现原理几乎一样,这就导致它们有两个非常相似的特性:

  1. 「元素不可重复」:dict 的键(key)不能重复,set 的元素本身就不能重复;
  2. 「查找速度极快」:不管里面存了10个元素还是10万个元素,查找/判断一个元素是否存在的时间复杂度都是 O(1)(平均情况),比列表(list)的 O(n) 快得多。

也正因为这两个共同点,才让很多初学者混淆了它们的用途。但记住:「相似的底层实现,是为了支撑不同的业务场景」。

核心差异:dict 存“映射关系”,set 存“独立元素”

这是两者最本质的区别,用一句话就能概括:

dict 是“键值对”的集合,核心是 「“映射”」(通过 key 找 value);set 是“唯一元素”的集合,核心是 「“去重”和“集合运算”」。

我们用两个简单的例子,直观感受下:

例子1:用 dict 存“映射关系”

如果我们要存储“学生姓名”和“学号”的对应关系,用 dict 最合适:

# 字典:姓名(key)→ 学号(value)student_id = {"张三": "2024001","李四": "2024002","王五": "2024003"}# 核心操作:通过 key 找 valueprint(student_id["李四"])  # 输出:2024002

这里的关键是“对应关系”——我们关心的不只是“张三、李四”这些名字本身,更关心每个名字背后对应的学号。dict 的设计初衷,就是为了高效地实现这种“键到值”的映射。

例子2:用 set 做“去重”和“集合运算”

如果我们只需要存储“班级里的学生姓名”,并且要保证没有重复,还要快速判断某个学生是否在班级里,这时候 set 就比 dict 更合适:

# 集合:存储唯一的学生姓名class_students = {"张三", "李四", "王五", "张三"}  # 重复的“张三”会自动去重print(class_students)  # 输出:{'张三', '李四', '王五'}# 核心操作1:判断元素是否存在print("赵六"in class_students)  # 输出:False# 核心操作2:集合运算(交集、并集、差集)another_class = {"李四", "王五", "赵六"}# 两个班级的共同学生(交集)print(class_students & another_class)  # 输出:{'李四', '王五'}# 两个班级的所有学生(并集)print(class_students | another_class)  # 输出:{'张三', '李四', '王五', '赵六'}# 本班有但另一个班没有的学生(差集)print(class_students - another_class)  # 输出:{'张三'}

这里的关键是“独立元素的集合特性”——我们只关心“哪些学生存在”,不关心他们对应的其他信息。而且 set 原生支持「交集、并集、差集」这些数学集合运算,这是 dict 完全不具备的能力。

如果只用 dict 代替 set,会怎么样?

有人可能会说:我不用 set,只用 dict 也能实现去重啊!比如把 dict 的 value 设为 None,用 key 来存唯一元素:

# 用 dict 模拟 set 去重fake_set = {"张三": None, "李四": None, "王五": None}# 判断元素是否存在print("张三"in fake_set)  # 输出:True

确实能实现,但这样做有两个明显的问题:

  1. 「语义不清晰」:dict 的本质是映射,你强行把它当成“唯一元素集合”来用,别人看你的代码会很困惑——这个 None 是什么意思?是不是遗漏了什么信息?代码的“可读性”会变差;
  2. 「冗余且低效」:你需要为每个元素额外存储一个无用的 value(比如 None),虽然占用的内存不多,但本质上是一种浪费。而且 dict 不支持集合运算,如果你想做交集、并集,还得自己写循环实现,既麻烦又比 set 原生的运算慢。

举个例子:用 dict 模拟两个集合的交集,你得这么写:

set1 = {"a": None, "b": None, "c": None}set2 = {"b": None, "c": None, "d": None}# 模拟交集:找出两个 dict 中共同的 keyintersection = [k for k in set1 if k in set2]print(intersection)  # 输出:['b', 'c']

而用 set 只需要一行 set1 & set2,简洁又高效。这就是 set 存在的意义——它把“去重”和“集合运算”这些场景封装成了原生功能,让你不用重复造轮子。

总结:什么时候用 dict,什么时候用 set?

记住两个核心场景,再也不会混淆:

用 dict 的情况:

  • 需要存储“键值对”映射关系(比如:姓名→年龄、ID→数据、配置项名称→配置值);
  • 需要通过一个唯一标识(key)快速查找对应的数据(value)。

用 set 的情况:

  • 只需要存储“唯一的元素”(比如:去重后的列表、用户ID集合、标签集合);
  • 需要快速判断一个元素是否存在于集合中;
  • 需要进行集合运算(交集、并集、差集,比如:两个用户群体的重合度、标签筛选)。

最后补一个小知识点

其实从底层实现来看,set 本质上就是一个“没有 value 的 dict”——它只存储 key,并且保证 key 的唯一性。正因为如此,set 的元素也必须是“可哈希”的(比如:字符串、数字、元组,不能是列表、字典),这和 dict 的 key 要求是一样的。

Python 设计团队没有把 set 的功能整合到 dict 里,而是单独作为一个数据类型,核心就是为了「明确语义、简化使用」——让每个数据类型都有自己最擅长的场景,这样写出来的代码才更清晰、更易维护。

所以,下次再纠结“用 dict 还是 set”的时候,先问自己:我是要存“映射关系”,还是要存“唯一元素”?想清楚这个问题,答案就出来了~

长按或扫描下方二维码,免费获取 Python公开课和大佬打包整理的几百G的学习资料,内容包含但不限于Python电子书、教程、项目接单、源码等等

▲扫描二维码-免费领取

推荐阅读

Python 鸭子类型:优雅的多态哲学,让代码更自由

探索动态类型编程:深入理解鸭子类型

前端走进机器学习生态,在 Node.js 中使用 Python

Python和Node.js,应该选择哪种编程语言

点击 阅读原文了解更多

最新文章

随机文章