Python 的 dict 和 set —— 有无value的区别

Python 的 dict 和 set ,

假如你是一名你是厨师,厨房有 100 个调料罐,想拿"花椒"。

  • 方案一 :调料罐排成一排,没标签。你从第一个开始找,最坏看 100 次。这叫 列表,查找时间 O(n)。
  • 方案二 :每个罐子贴标签,按首字母分抽屉。"花椒"去 H 抽屉,一步到位。这叫 字典,查找时间 O(1)。

数据量越大,差距越离谱:100 个调料差 100 倍,100 万个差 100 万倍。这就是今天要聊的核心------字典和集合为什么快,怎么用

2. 字典:带标签的抽屉

长什么样

python

ini 复制代码
kitchen = {'花椒': 5, '八角': 3, '香叶': 10}
print(kitchen['花椒'])   # 5

常用操作

python

python 复制代码
# 增/改
kitchen['桂皮'] = 2      # 新加
kitchen['花椒'] = 6      # 覆盖

# 查(安全版)
print(kitchen.get('草果'))     # None
print(kitchen.get('草果', 0))  # 0

# 判断存在
if '花椒' in kitchen:
    print('有花椒')

# 删
value = kitchen.pop('香叶')    # 返回10
del kitchen['八角']

一句话总结:字典是"键 → 值"的映射,查得快,但占内存。

3. 底层原理:哈希表是怎么做到"一步到位"的

你不用背哈希函数怎么写的,但理解原理能帮你避开很多坑。

  • 当你执行 kitchen['花椒'] = 5,Python 对 '花椒' 做哈希计算,得到一个整数,再算出数组中的位置,把 ('花椒',5) 存进去。
  • 读取时,同样的计算直接找到位置。

哈希冲突 :两个不同的 key 可能算出同一个位置(比如 '花椒''麻椒' 撞车了)。Python 会在那里放一个链表,把多个键值对串起来。冲突多了查找会变慢,所以字典会自动扩容(重新分配位置)。这个自动调整的过程叫 rehash

负载因子:当字典里的元素超过数组长度的 2/3,就会触发扩容。这就是为什么字典有时候突然变慢一下------它在搬家。

4. 性能对比:列表 vs 字典,以及"空间换时间"

写一段代码试试(10 万条数据):

python

bash 复制代码
# 列表查找:遍历找索引,再取值 → 约 0.005 秒
# 字典查找:直接取 → 约 0.000001 秒

结论 :字典查找比列表快几千倍。代价是内存------字典有很多空槽位,浪费空间。这叫空间换时间

应用场景

  • 统计词频word_count[word] = word_count.get(word, 0) + 1
  • 缓存计算结果(斐波那契数列 memoization)
  • 配置管理config = {'host':'localhost', 'port':8080}
  • 任何需要"根据一个名字/ID 快速找到对应东西"的地方

5. 遍历与高级用法

基本遍历

python

python 复制代码
for spice in kitchen:           # 遍历键
    print(spice)

for spice, amount in kitchen.items():   # 遍历键值对
    print(f'{spice}: {amount}克')

有序性 :Python 3.7+ 的字典保持插入顺序。所以你可以放心遍历,顺序就是你添加的顺序。

defaultdict 简化代码(不用手动判断 key 是否存在)

python

arduino 复制代码
from collections import defaultdict
word_count = defaultdict(int)
for word in text.split():
    word_count[word] += 1   # 自动初始化为0

其他小技巧

  • 判断是否存在直接用 key in dict,比 dict.keys()
  • 不要用字典做频繁的遍历和顺序访问------那是 list 的活
  • 数据量很小(<100)时,list 可能比 dict 快,因为哈希计算有开销

6. Set:只要标签,不要数字

有时候你只关心"厨房里有哪些调料",不关心还剩多少克。

python

go 复制代码
spices = {'花椒', '八角', '香叶', '花椒'}   # 重复自动去掉
print(spices)   # {'花椒', '香叶', '八角'}  顺序不固定

Set 的核心:自动去重 + O(1) 成员判断

基本操作

python

csharp 复制代码
s = {1, 2, 3}
s.add(4)
s.remove(2)        # 不存在会报错
s.discard(5)       # 不存在不报错
if 3 in s:
    print('在')

去重神器

python

c 复制代码
unique_names = set(['张三', '李四', '张三', '王五'])
# 或直接:set(['张三', '李四', '张三', '王五'])

7. Set 的集合运算与应用

集合运算

python

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

实际应用

  • 共同好友my_friends & her_friends
  • 推荐好友her_friends - my_friends
  • 数据清洗(剔除黑名单)[e for e in emails if e not in blacklist]
  • 快速去重 :统计一篇文章中出现了哪些单词------set(text.split())

8. 关键约束与注意事项(容易踩坑的地方)

(1)字典的 key 必须不可变

python

ini 复制代码
d = {}
key = [1,2,3]
d[key] = 'error'   # TypeError: unhashable type: 'list'

列表可变,哈希值会变,不能做 key。字符串、数字、元组(且元组内元素不可变)可以。

如果非要用列表当 key,转成元组:key = tuple([1,2,3])

(2)可变与不可变对象的区别

python

ini 复制代码
s = 'abc'
s.replace('a', 'A')   # 返回新字符串,原 s 不变
lst = [1,2,3]
lst.append(4)         # 原列表变了

理解这个,才能理解为什么列表不能做 key。

(3)Set 不保证顺序

虽然 dict 从 Python 3.7 开始有序,但 set 仍然是无序的。不要依赖 set 的顺序。

(4)性能小提示

  • 创建 dict/set 比 list 慢(要算哈希)
  • 适合"查得多、写得少"的场景
  • 数据量小的时候直接用 list 可能更省事

小结:一张表记住怎么选

场景 选哪个 原因
需要顺序、频繁遍历 list 内存小,顺序明确
根据名字快速查值 dict O(1) 查找
只关心"有没有出现过" set 自动去重 + 快速存在判断
统计次数 dict / defaultdict 键为元素,值为次数
集合关系(共同、差异等) set 直接支持交并差

dict 和 set 是 Python 里的"快查手册",list 是"从头翻的流水账"。搞懂它们的区别,代码跑得更快,脑子也更清楚。

相关推荐
编程探索者小陈1 小时前
接口自动化测试(一)
python·测试
峥嵘life1 小时前
Android 蓝牙设备连接广播详解-2026
android·python·学习
郝学胜-神的一滴2 小时前
干货版《算法导论》07:递归视角下的选择排序与归并排序
java·数据结构·c++·python·程序人生·算法·排序算法
shehuiyuelaiyuehao2 小时前
多线程入门
java·python·算法
Oo9202 小时前
Prompt工程核心与Python 字典
python·ai编程
feeday3 小时前
gpt4o 图像反推提示词
开发语言·人工智能·python
沈浩(种子思维作者)3 小时前
没有错误,正确将一文不值
人工智能·python·算法·量子计算
smith成长之旅3 小时前
06 | Mem0 框架分析:为什么要从记忆中提取实体?——Entity Store 的设计动机与工程实现
人工智能·python
smith成长之旅3 小时前
07 | Mem0 框架分析:三路信号融合——语义 + BM25 + Entity Boost 的混合检索
python·算法