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 是"从头翻的流水账"。搞懂它们的区别,代码跑得更快,脑子也更清楚。

相关推荐
老白干29 分钟前
jjwt 0.9.1 在 JDK 11+ 上的两个“坑”与完整解决方案
java·python·log4j
笨鸟先飞,勤能补拙7 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
长和信泰光伏储能8 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂8 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study9 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境9 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境10 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd12310 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy123931021610 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb0011 小时前
一个项目带你入门AI应用开发01
python