Python 去重实测:set 比 dict.fromkeys 快,但只有它保序
【摘要】 很多人说 dict.fromkeys 去重比 set 快。我用 Python 3.13 在 10 的三次方到 10 的六次方规模实测,结论相反:set 更快、内存更低。dict.fromkeys 的真正价值是保留首次出现顺序。
一句话结论
- 不关心顺序时,
set(x)比list(dict.fromkeys(x))快 30% 到 100%,多数规模下内存也更低 dict.fromkeys唯一不可替代的价值是保留首次出现顺序,为这个顺序付的时间是实打实的,不是「免费」的- 网上「dict.fromkeys 去重比 set 快」的说法,在 Python 3.13 实测里不成立
场景
- 日志去重后统计:只关心「出现过哪些」,顺序无所谓,用
set最快 - 列表去重还要保住原来的先后次序(比如保留用户点击顺序):只能用
list(dict.fromkeys(x)) - 很多教程把 dict.fromkeys 当成「既保序又更快」的银弹,这个结论我怀疑过,于是直接跑了基准
第一版基准
- 机器:i5-4590(4 核 4 线程)/ Python 3.13.14 / Windows 10
- 数据:随机整数,两种重复率(dup=0.1 表示 10% 重复、dup=0.9 表示 90% 重复),四档规模 10³ 到 10⁶
- 每项取 5 轮中位,时间单位毫秒
实测数字
- n=1000, dup=0.1:set=0.016ms,dict=0.026ms,list(set)=0.016ms
- n=10000, dup=0.1:set=0.256ms,dict=0.394ms,list(set)=0.254ms
- n=100000, dup=0.1:set=3.760ms,dict=8.430ms,list(set)=5.376ms
- n=1000000, dup=0.1:set=158.355ms,dict=248.423ms,list(set)=158.998ms
- n=100000, dup=0.9:set=9.201ms,dict=14.850ms,list(set)=8.425ms
- n=1000000, dup=0.9:set=176.762ms,dict=318.259ms,list(set)=198.065ms
排查:为什么 set 反而更快
set是单张哈希表;dict.fromkeys建的是完整字典(每个键还带着一个 value 槽),每元素开销更大- 内存峰值:n=10⁶、dup=0.9 时,dict 峰值约 30MB,set 约 24MB
list(set(x))这种「先 set 再转 list」的写法,时间上和set(x)几乎一样,但丢掉顺序
顺序才是 dict.fromkeys 的存在理由
- 验证:
list(dict.fromkeys([3,1,3,2,1,3]))结果是[3,1,2],保住了首次出现顺序 set不保证插入顺序,下面这个反例一眼能看清:['banana','apple','cherry','date','elderberry','fig','grape']经过set后变成['date','apple','fig','elderberry','cherry','grape','banana']- 所以「保序」是选
dict.fromkeys的唯一正当理由,不是「它更快」
选型建议
- 只要去重、不关心顺序:直接
set(x),最快最省内存 - 要去重且必须保住先后次序:
list(dict.fromkeys(x)),但要接受约 1.5 倍时间和更高的内存 - 千万别为了「更快」而用
dict.fromkeys——在 3.13 上它并不快 - 哈希不可用的对象(如带状态的自定义类)两种写法都不行,需要先定
__hash__与__eq__
最后一句
- 用对工具:要快用
set,要序用dict.fromkeys,别被过时结论带偏,跑一遍比看十篇博客靠谱
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)