卡码笔记-最强八股文
首页
计算机基础
Python
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
大模型Github (opens new window)
代码随想录 (opens new window)
首页
计算机基础
Python
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
大模型Github (opens new window)
代码随想录 (opens new window)
  • 本栏必读

    • Python面试题专栏介绍
    • Python学习路线
    • Python零基础入门课
  • 基础语法

    • Python有哪些内置数据类型?
    • Python变量保存的是什么?
    • 可变对象和不可变对象有什么区别?
    • is和==有什么区别?
    • Python的运算符有哪些?
    • Python条件判断和循环的常见写法与易错点
    • Python字符串为什么不可变?
    • Python列表和元组有什么区别?
    • Python字典和集合有什么区别?
      • 简要回答
      • 详细回答
      • 知识拓展
    • Python切片和序列解包怎么用?
    • 列表、字典和集合推导式怎么写?
  • 函数、作用域与模块

  • 面向对象

  • 进阶语法与语言机制

# Python字典和集合有什么区别?

面试官问:“Python中的字典和集合有什么区别?”

很多人会回答“字典有键值对,集合只有值”就停了,但这只是表象。要讲清楚这道题,关键是说明它们共享的底层结构(哈希表)、为什么查找都是O(1)、键和元素的可哈希要求,以及各自解决什么问题。

# 简要回答

字典(dict)存储键值对,集合(set)只存储唯一元素。 两者在CPython中都基于哈希表实现,所以查找、插入和删除操作的平均时间复杂度都是O(1)。

字典的键必须可哈希,值可以是任意对象;集合的元素也必须可哈希。字典用于快速根据键查找对应的值,集合用于去重、成员测试和集合运算(交集、并集、差集)。

从Python 3.7开始,字典保证按插入顺序迭代;集合不保证元素顺序。

# 详细回答

# 底层都是哈希表,但用途不同

字典和集合都使用哈希表存储数据,这是它们查找速度快的原因。插入元素时,Python计算对象的哈希值,根据哈希值找到存储位置;查找时用同样的方式直接定位,不需要遍历。

字典存储的是键值对:

user = {"name": "Alice", "age": 25}
print(user["name"])  # Alice
1
2

集合只存储元素本身,自动去重:

tags = {"Python", "Java", "Python"}
print(len(tags))  # 2
1
2

第二个"Python"被自动忽略,因为集合保证元素唯一性。集合打印出来的顺序不固定,这里只看长度。

字典与集合的哈希结构对比

图中展示了字典和集合虽然都基于哈希表,但字典存储键到值的映射,集合只记录元素本身,且利用哈希表的特性自动去重。

# 可哈希要求

字典的键和集合的元素都必须可哈希。 常见的可哈希类型包括:整数、浮点数、字符串、frozenset,以及所有元素都可哈希的元组。元组能不能当键,取决于里面装了什么,这一点在《Python列表和元组有什么区别?》里有展开。

可哈希和不可变密切相关,但不完全等价,背景可以先看《Python中的可变对象和不可变对象有什么区别?》。

列表、字典、集合本身都是可变对象,不能作为键或集合元素:

# 可以
courses = {("Python", 3): "进阶课"}
tags = {1, "Python", (2024, 10)}

# 不行
try:
    invalid = {["Python"]: "课程"}
except TypeError as e:
    print(e)  # unhashable type: 'list'
1
2
3
4
5
6
7
8
9

判断一个对象是否可哈希,可以调用hash():

print(type(hash("Python")).__name__)  # int
hash([1, 2])  # TypeError: unhashable type: 'list'
1
2

# 操作对比

操作类型 字典 集合
创建 {"a": 1} 或 dict() {1, 2} 或 set()
查找 d[key] 或 d.get(key) elem in s
插入/更新 d[key] = value s.add(elem)
删除 del d[key] 或 d.pop(key) s.remove(elem) 或 s.discard(elem)
长度 len(d) len(s)
迭代 for k in d: 或 d.items() for elem in s:
集合运算 不支持 交集、并集、差集、对称差

字典可以用d.keys()、d.values()、d.items()分别迭代键、值、键值对。集合支持数学集合运算:

a = {1, 2, 3}
b = {2, 3, 4}
print(a & b)  # {2, 3}       交集
print(a | b)  # {1, 2, 3, 4} 并集
print(a - b)  # {1}          差集
print(a ^ b)  # {1, 4}       对称差
1
2
3
4
5
6

字典不支持这些运算符,但Python 3.9+可以用|合并字典:

d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
print(d1 | d2)  # {'a': 1, 'b': 3, 'c': 4}
1
2
3

# 顺序保证

从Python 3.7开始,字典保证按插入顺序迭代。这原本是CPython 3.6的实现细节,3.7正式纳入语言规范。

集合不保证顺序,迭代顺序可能随实现和哈希碰撞情况变化:

d = {"c": 3, "a": 1, "b": 2}
print(list(d.keys()))  # ['c', 'a', 'b'] 保证插入顺序

s = {"c", "a", "b"}
print(list(s))  # 顺序不确定,可能是 ['a', 'b', 'c'] 或其他
1
2
3
4
5

需要有序集合时,可以用dict.fromkeys()模拟:

ordered_unique = list(dict.fromkeys(["c", "a", "b", "a"]))
print(ordered_unique)  # ['c', 'a', 'b']
1
2

# 知识拓展

面试官可能追问:

Q1:为什么字典查找是O(1),而不是O(n)?

因为字典基于哈希表。给定键后,Python计算其哈希值并直接定位到存储位置,不需要遍历所有键。这是平均情况;大量哈希冲突时,最坏情况会退化到O(n)。

Q2:空集合应该用{}还是set()?

{}创建的是空字典,不是空集合。空集合必须用set():

empty_dict = {}
empty_set = set()
print(type(empty_dict).__name__)  # dict
print(type(empty_set).__name__)   # set
1
2
3
4

Q3:字典的值可以是列表或字典吗?

可以。字典只要求键可哈希,值可以是任意对象,包括可变对象:

data = {"users": ["Alice", "Bob"], "config": {"debug": True}}
1

Q4:集合能用索引访问吗?

不能。集合是无序的,没有索引概念。需要访问集合中某个元素时,要么遍历,要么转成列表:

s = {1, 2, 3}
# s[0]  # TypeError
first = list(s)[0]  # 可以,但顺序不保证
1
2
3

Q5:什么时候用字典,什么时候用集合?

字典用于键值映射:统计频次、缓存、配置管理、快速查表。集合用于去重、成员测试、集合运算。如果只关心“某个元素是否存在”,用集合;如果需要“根据键查找对应的值”,用字典。

Last Updated: 10/13/2026, 5:57:00 PM

← Python列表和元组有什么区别? Python切片和序列解包怎么用? →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪