使用dict和set
在Python的内置数据结构里,列表和元组用来存有序序列已经足够顺手,但遇到快速通过「唯一标识」定位数据、一键批量去重、高效成员关系判断这种高频场景,「字典dict」和「集合set」绝对是不可替代的黄金搭档——核心原因是它们底层都用了哈希表(Hash Table) 的“黑科技”!
字典(dict)基础
Python的字典是典型的键值对(key-value)映射容器,其他语言中也叫哈希表(Hash Table)、映射(Map)、关联数组(Associative Array)等。
基本的增删改查
字典的语法非常直观,用花括号包裹key: value对,逗号分隔。
高效性的核心:哈希表原理
字典为什么能做到接近O(1)的查询/插入/删除速度?简单来说是靠三步:
- 对输入的
key执行内置的哈希函数hash(),得到一个固定的“哈希值编码” - 把哈希值编码压缩成容器内部数组的索引位置
- 根据索引直接定位到
value的存储地址
整个过程不需要遍历所有元素,所以数据量从10涨到10000,速度基本没变化。
常用的进阶操作
三个不能忘的核心特点
- 插入有序(语言规范3.7+),但别完全依赖:Python 3.6+是实现层面有序,3.7+写入了规范,但跨版本或底层优化后可能调整逻辑,业务强依赖顺序请用
collections.OrderedDict - 键必须唯一:后赋值的同键会直接覆盖前一个
- 键必须是不可变对象:哈希表需要稳定的哈希值,可变对象(列表、字典、普通集合)的哈希值会随内容变,会破坏内部索引结构
集合(set)基础
集合可以理解成只存键、不存值的字典,底层同样靠哈希表实现,天生适合做去重和集合运算。
基本的使用和运算
集合的三个核心特点
和字典的键几乎一致:
- 无序性:同样不要依赖遍历顺序
- 唯一性:自动去重是最大优势
- 元素必须是不可变对象:比如可以加字符串、数字、元组,不能加列表
关键前置:可变与不可变对象
不管是字典的键还是集合的元素,都对“不可变”有要求,这里快速梳理一下区别:
可变对象(Mutable)
创建后内容可以直接修改,内存地址不变:
- 列表(list)、字典(dict)、普通集合(set)
不可变对象(Immutable)
创建后内容不能直接修改,修改只能生成新对象:
- 字符串(str)、数字(int/float/bool)、元组(tuple)、
frozenset(冻结集合,专门当键/集合元素用的不可变集合)
实际应用场景建议
什么时候用dict?
- 键值对映射查询:比如根据学号查姓名、根据API请求的参数名取参数
- 数据分组统计:比如统计一段文本中每个单词的出现次数
- LRU/简单缓存:利用哈希表的O(1)查找速度实现快速缓存
什么时候用set?
- 批量去重:比如从用户提交的重复表单ID中提取唯一ID
- 高效成员关系判断:比如检查一个IP是否在黑名单里(比列表遍历快100倍以上)
- 简单集合逻辑:比如找两个用户的共同好友、找网站今日新增的独立访客
简单的性能对比(仅参考)
高频小问题解答
Q: 为什么列表不能当字典的键或集合的元素?
A: 因为列表是可变的!如果允许用列表当键,假设我们先存了d = {[1,2]: "a"},然后修改列表lst = [1,2]为[3,4],哈希值会变,原来的索引位置就找不到对应值了,还会造成内存泄漏。如果需要用类似序列的键,可以转成元组:
Q: Python 3.7+字典保持插入顺序了,还要OrderedDict吗? A: 分情况:
- 只是想遍历顺序和插入一致:普通dict足够(3.7+)
- 需要双向操作(比如把最后插入的键移到最前面) 或者兼容3.7以前的版本:必须用
collections.OrderedDict

