Python 去重实测:set 比 dict.fromkeys 快,但只有它保序

举报
yd_232353574 发表于 2026/10/29 08:31:00 2026/10/29
【摘要】 很多人说 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)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。