Python字典为什么查得快详解(3个实验看懂哈希表底层)

 更新时间:2026年10月22日 09:15:55   作者:青春不朽512  
字典(dict)是Python中常见的数据结构,用于存储键值对,这篇文章主要介绍了Python字典为什么查得快的相关资料,文中通过3个实验看懂哈希表底层,需要的朋友可以参考下

系列:Python 底层设计逻辑|类型:原理拆解型|分发:CSDN / 博客园 / 腾讯云
字数:约 1600 字

结论先行:dict 查得快,不是因为它"会找",而是因为它"会算"——用键的哈希值直接算出该去哪个槽位拿数据,理论上一步到位,和字典里存了多少个键几乎无关。但这份快是有代价的:键必须可哈希、查找实际是 O(1) 平均而非最坏、还白放着约三分之一的内存。这三个坑,用三个实验看清楚。

1. 先建立直觉:dict 不是"表",是"带传送门的格子间"

列表查一个值,得从第 0 个开始比,最坏翻到底——O(n)。字典不干这事:

d = {'name': '张三', 'age': 18}
d['age']          # 不是遍历,是 hash('age') → 算出槽位 → 直接取

每个键进来,先算 hash(key),再按槽位数量取模,落进对应的格子。查找同理:算一次哈希,去对应格子拿。格子数远大于元素数时,一步就中。

2. 实验一:10 万个键,dict 和 list 差多少

import time

N = 100000
lst = list(range(N))
dct = {i: i for i in range(N)}
target = N - 1                     # 查最后一个,list 的最坏情况

t0 = time.perf_counter()
_ = target in lst
t1 = time.perf_counter()
_ = target in dct
t2 = time.perf_counter()

print(f'list: {(t1-t0)*1000:.3f} ms')
print(f'dict: {(t2-t1)*1000:.3f} ms')

典型输出:list 要几百毫秒,dict 只要几微秒——差 2~3 个数量级。把 N 再放大 10 倍,dict 的时间几乎不变,list 线性变长。 这一条就是"哈希表 O(1)"的体感。

3. 实验二:哈希冲突是常态,不是事故

槽位总比键少,冲突必然发生。CPython 用开放寻址(探测下一个空槽)解决:

# 构造一批"爱打架"的键:哈希值对 8 同余
keys = [i for i in range(64) if hash(i) % 8 == 0]
d = {k: k for k in keys}
print(len(d))                      # 8 个键全在,查找依然正确

为什么重要:冲突不丢数据,但会让查找从"一步"变成"探几步"。键太集中(或有人恶意构造碰撞键)时,dict 会退化成慢查找——这也是为什么 PYTHONHASHSEED 默认随机化:让攻击者算不出你的字符串哈希。

4. 实验三:为什么 list 不能做键

d = {}
d[[1, 2]] = 'x'        # TypeError: unhashable type: 'list'
d[(1, 2)] = 'x'        # tuple 可以
print(d)               # {(1, 2): 'x'}

为什么翻车:list 内容能改,改了哈希就变了——今天算出的槽位在 A,明天值一改槽位算到 B,字典就永远找不到它了。所以 Python 要求键可哈希:hash() 能算、且对象生命周期内哈希不变(不可变)。tuple 元素全不可变时才可哈希:([1],) 照样报错。

5. 两个反直觉点

① dict 有序且"记性"在键上:Python 3.7+ dict 保序,但这是实现细节顺带的福利,别依赖它做业务逻辑。

② 空 dict 不省多少,装满才扩容:dict 元素超过容量的 2/3 会触发扩容(重新哈希全部键,一次性 O(n))。所以预分配大字典没有意义——扩容均摊下来仍是 O(1)。

6. dict vs set vs list(选型对照)

维度dictsetlist
查找O(1) 平均O(1) 平均O(n)
键/元素要求可哈希可哈希无要求
存什么键→值去重的键有序序列
内存偏高(约 1/3 空闲槽)偏高紧凑
典型场景映射/缓存/计数去重/成员判断顺序处理

对照结论:按 key 取值 → dict;只问"在不在" → set;要顺序、要索引 → list。别用 list 做"存在性检查",数据一上万就是灾难。

到此这篇关于Python字典为什么查得快的文章就介绍到这了,更多相关Python字典查得快内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • numpy增加维度、删除维度的方法

    numpy增加维度、删除维度的方法

    本文主要介绍了numpy增加维度、删除维度的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 使用pyecharts无法import Bar的解决方案

    使用pyecharts无法import Bar的解决方案

    这篇文章主要介绍了使用pyecharts无法import Bar的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-01-01
  • 前女友发来加密的

    前女友发来加密的"520快乐.pdf",我用python破解开之后,却发现

    520收到前女友发来的加密PDF文件,说打开之后有惊喜,难道是要复合?我用python破解开之后,却发现...python干货+剧情满满收藏收藏
    2021-08-08
  • PyQt中使用QTabWidget实现多页面布局的方法

    PyQt中使用QTabWidget实现多页面布局的方法

    在使用PyQt编写桌面应用程序的过程中,要实现多页面布局方案,可以使用QTabWidget控件来实现,本案例提供了完整的标签页管理功能,同时保持了响应式设计的核心原则,能够很好地适应不同屏幕尺寸和内容变化,感兴趣的朋友一起看看吧
    2025-04-04
  • Django零基础入门之自定义标签及模板中的使用

    Django零基础入门之自定义标签及模板中的使用

    这篇文章主要介绍了Django零基础入门之自定义标签及模板中的使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • python设置检查点简单实现代码

    python设置检查点简单实现代码

    这篇文章主要介绍了python设置检查点简单实现代码,需要的朋友可以参考下
    2014-07-07
  • Python和Anaconda的版本对应关系

    Python和Anaconda的版本对应关系

    这篇文章主要为大家介绍了Python和Anaconda,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • 如何在Python中使用pyecharts图形画可视化大屏

    如何在Python中使用pyecharts图形画可视化大屏

    最近碰巧需要用到pyecharts,pyecharts库是一个用于生成echarts图表的类库,这篇文章主要给大家介绍了关于如何在Python中使用pyecharts图形画可视化大屏的相关资料,需要的朋友可以参考下
    2024-05-05
  • PyTorch中torch.matmul()函数常见用法总结

    PyTorch中torch.matmul()函数常见用法总结

    torch.matmul()也是一种类似于矩阵相乘操作的tensor连乘操作。但是它可以利用python中的广播机制,处理一些维度不同的tensor结构进行相乘操作,这篇文章主要介绍了PyTorch中torch.matmul()函数用法总结,需要的朋友可以参考下
    2023-04-04
  • python 实现在shell窗口中编写print不向屏幕输出

    python 实现在shell窗口中编写print不向屏幕输出

    这篇文章主要介绍了python 实现在shell窗口中编写print不向屏幕输出的代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02

最新评论