Python 字典为什么这么快?一次查找背后的哈希表、扰动函数和开放寻址

简介: Python 字典查找平均 O(1):算一次哈希直接跳到桶位,实测 1 万 key 取值 4.6ms,同规模列表成员判断要 55 秒,差 12000 倍;但哈希全碰撞时慢 2111 倍——用 4 组实验讲透开放寻址、扰动函数和空间换时间。

结论先行:Python 字典查找的平均耗时是 O(1),代价是哈希计算;本文实测 1 万个 key 的取值只要 4.6ms,而同样规模的列表成员判断要跑近 55 秒——差了约 12000 倍。但字典不是无条件快:一旦 key 的哈希值大面积撞桶,性能会断崖式下跌,本文构造全碰撞场景实测慢了 2111 倍。这篇用 4 组实验把「为什么快」和「什么时候不快」一次讲透。


1. 先看一组反常识的实验结果

import timeit, random
N = 1_000_000
d = {
   i: i for i in range(N)}
lst = list(range(N))
keys = [random.randrange(N) for _ in range(10000)]

# dict 取值
t_dict = timeit.timeit(lambda: [d[k] for k in keys], number=1)
# list 成员判断(只跑 200 个,否则跑不完)
t_list = timeit.timeit(lambda: [k in lst for k in keys[:200]], number=1)

实测结果:

操作 次数 耗时 折算每次
dict 取值 10000 次 4.6 ms 0.46 μs
list 成员判断 200 次 1099.8 ms 5.5 ms
list 成员判断(折算) 10000 次 约 55000 ms —

差了四个数量级。列表判断一次要扫半个表,100 万个元素的中位数就是 50 万次比较——55 秒这个数字听起来离谱,但它就是 O(n) 的本来面目。

字典的秘诀只有一句话:算一次哈希,直接跳到桶的位置。 中间的 49.9 万个元素,它一个都没看。

2. 桶里面是什么:开放寻址

CPython 的字典不是「桶里挂链表」(那是 Java HashMap 的做法),而是开放寻址:一张表,每个槽存一个 (hash, key, value) 三元组。

查找过程就三步:

1. h = hash(key)
2. 用 h 的低位定位起始槽位
3. 从该槽位开始线性探测,比对 hash 相等且 key 相等,命中

插入同理:找到第一个空槽放进去。所以哈希相等还不够,最终必须回到 == 比较——这解释了为什么不可哈希的对象(如 list)不能做 key:它连第一步都过不去。

3. 扰动函数:hash 值不能直接用

看一组真实 hash 值:

>>> hash(1)
1
>>> hash('a')
2161380871107616833

hash(1) = 1、hash(2) = 2、hash(3) = 3……如果直接拿小整数当槽位索引,连续整数键会把前 N 个槽位占满,后面的键全部撞在同一区域,开放寻址当场退化成线性扫描。

CPython 的解法是扰动函数:把 hash 值的高位混进低位,让分布更均匀。这也是为什么整数键和字符串键的查找速度有差距(本文实测:2000 个整数键 0.13ms,2000 个字符串键 0.20ms)——字符串要先算哈希,整数直接就是哈希。

4. 一张表看懂:dict / set / list 的定位差异

维度 dict set list
查找复杂度 平均 O(1) 平均 O(1) O(n)
靠什么定位 哈希 + 开放寻址 同 dict(只存 key) 顺序扫描 + ==
10000 次查找(实测) 4.6 ms 3.0 ms 约 55000 ms
key 要求 可哈希 可哈希 无要求
内存(10 万元素实测) 8.2 MB 约 8 MB 0.8 MB

set 和 dict 底层是同一套哈希表代码(set 就是「只有 key 的 dict」),所以二者速度同级。list 省内存但慢,dict 快但费内存——这是一笔明码标价的空间换时间。

5. 什么时候会翻车:全碰撞实测慢 2111 倍

字典的 O(1) 有个前提:哈希分布均匀。如果所有 key 撞进同一个桶,开放寻址就变成了「沿着槽位一个一个问」。

class Collide:
    def __init__(self, v): self.v = v
    def __hash__(self): return 42        # 全部撞同一个桶
    def __eq__(self, o): return isinstance(o, Collide) and self.v == o.v

cd = {
   Collide(i): i for i in range(2000)}

实测 2000 个 key:

场景 2000 次取值耗时
正常整数键 0.13 ms
哈希全为 42 的自定义对象 271.31 ms

慢 2111 倍,O(1) 直接变成 O(n)。 这不是 bug,是哈希表的本性——它赌的就是「哈希值足够散」。Web 框架被 hashDoS 攻击打穿过一轮之后,Python 给字符串哈希加了随机盐(每次进程启动 hash('a') 都可能不同),就是为了让攻击者算不出必撞的输入。

所以自定义 __hash__ 时,让它全返回常量是最省事也最危险的写法。

6. 实用结论

  1. 成员判断、去重、计数,永远优先 dict/set,不要用 in list——本文 12000 倍的差距就是日常代码里最大的性能分水岭之一。
  2. key 优先用字符串或整数:自带稳定的哈希,省一次计算。
  3. 自定义对象做 key,__hash__ 必须分布均匀,全常量等于主动放弃 O(1)。
  4. dict 费内存是设计使然:每个槽要存 hash、key、value 三份信息,10 万元素约 8MB,敏感场景可考虑 __slots__ 类或元组列表替代。

(全文完)

相关文章
|
1天前
|
JSON 缓存 C语言
Python 的 True + True 为什么等于 2?bool 是 int 子类,这个设计坑了多少人
True+True==2、isinstance(True,int) 为真:bool 是 int 的子类,True 就是 1。9 组实验讲透这个 C 时代设计遗产的顺手与埋雷——字典键碰撞、JSON 序列化、== 与 is 混用三大坑一次避开。
|
8天前
|
Python
Python 迭代器和生成器到底啥区别?3 个例子讲透,别再背概念了
迭代器和生成器不是并列关系——生成器是迭代器的一种“偷懒写法”。3 个例子讲透:迭代器是“会挨个吐值的对象”,生成器是用 yield 现写现用的那种,最大区别是它懒,要一个才生一个。
|
9天前
|
Python
Python 装饰器到底是个啥?从 @ 符号到手写一个,5 个例子讲透
装饰器(decorator)本质是一个「接收函数、返回函数」的高阶函数,@log 写在 def foo() 上等价于 foo = log(foo)。本文从最朴素的包装工厂讲起,用 5 个例子把 @ 语法、functools.wraps、带参数装饰器、类装饰器一次讲透。
|
12天前
|
缓存 Python
Python 装饰器把函数"搞丢"了?5 个必踩的坑与完整避坑对照表
装饰器的坑不是"不会写",而是写完原函数被悄悄换掉——名字、文档、签名、身份都可能变。functools.wraps 救得回大部分,救不了全部。5 个坑逐个给复现代码和修法,附完整对照表。
|
7月前
|
人工智能 Linux API
OpenClaw全自动小红书运营实战:从0到1全流程部署、技能配置与内容自动化发布指南
在内容自动化运营场景中,OpenClaw(Clawdbot)凭借高度可扩展的Skill体系与多任务执行能力,可实现从热点追踪、文案创作、封面生成到笔记发布、互动管理的全流程自动化。本文基于2026年最新环境,完整讲解如何通过阿里云轻量服务器或本地Windows11/macOS/Linux部署OpenClaw,安装并配置小红书运营Skill,完成Cookie登录、内容生成、笔记发布、数据监控,并接入阿里云百炼Coding Plan免费大模型与QMD记忆优化系统,实现低成本、7×24小时无人值守小红书运营。全文无营销词汇,所有命令可直接复制,零基础用户也能快速跑通全流程。
3431 9
|
1月前
|
存储 人工智能 Linux
告别云端扣费:Ollama离线LLM部署全解,环境变量、命令集、Python/curl代码实战
随着大模型技术普及,越来越多开发者、科研人员、AI爱好者开始关注本地私有化大模型方案。云端API虽然上手简单,但会产生持续调用开销,业务对话、企业敏感文档数据需要向外传输,存在隐私泄露隐患。Ollama是一款免费开源的本地大模型运行框架,支持Windows、macOS、Linux全操作系统,能够在个人电脑或者服务器本地运行各类开源大模型,断网环境依旧可以正常提供AI推理能力,全部业务数据保存在本机,不需要上传至外部服务。当前主流版本为v0.32.x,模型库汇集Qwen、DeepSeek‑R1、Llama、Gemma、Qwen2.5‑VL多模态等海量开源模型,仅需一条终端命令就可以完成模型拉取、
427 0
|
25天前
|
人工智能 开发工具 git
刚刚 Opus 5.5 和 GPT-6 Sol 同时发布,首发实测来啦!结果让我很意外
5 大案例实战测评全新 Claude Opus 5.5 和 GPT-6 Sol 模型的 AI 编程和办公写作能力,2 大全新模型谁更强?谁的性价比更高?
440 0
|
2月前
|
XML JSON API
免费图书查询接口整理与使用教程
通过国际图书号查询图书信息,支持978开头及部分10位ISBN,可获取书名、作者、出版社、价格、出版日期、印次、装帧方式、畅销热度等。
1903 0
|
3月前
|
人工智能 IDE Java
阿里云Qoder CN v1.4.1全栈实战教程:Quest智能体、Repo知识库与MCP扩展完整落地
2026年阿里云完成原通义灵码品牌升级,正式推出Qoder CN稳定版v1.4.1,产品彻底脱离传统IDE代码片段补全工具定位,升级为目标驱动的全栈Agent式智能编程平台。区别于海外Cursor、GitHub Copilot仅支持局部代码生成的模式,Qoder CN依托Quest自主任务引擎、Repo项目知识库、MCP外部工具协议三大独有核心能力,可独立完成需求拆解、架构设计、批量多文件编码、自动化自测、项目文档沉淀全链路工程任务。本文完整梳理产品矩阵、分层算力体系、多端安装部署、百炼模型接入、三级编码规范、四大开发模式、MCP扩展能力,结合Spring Boot迁移、微服务拆分、分库分表、
650 0
|
10月前
|
弹性计算 安全 Linux
阿里云服务器购买指南:优惠攻略 + 自定义配置全流程(新手必看)
对于新手来说,购买阿里云服务器不仅要选对配置,更要抓住优惠福利。本文整合了阿里云服务器的两种核心购买方式—— 活动中心优惠购买与 ECS 自定义购买,详细拆解配置选择要点和操作步骤,帮你用最低成本选到合适的服务器,适配网站搭建、应用部署等多种场景。