dict.fromkeys()能保序去重是因为Python 3.7+字典保持插入顺序,其将元素依次作键插入,重复键被忽略,首次出现顺序即键序,list()提取键即得去重保序结果。

dict.fromkeys() 是当前最推荐的保序去重方式,前提是 Python ≥ 3.7 且元素可哈希。它比手动遍历快一个数量级,也比 OrderedDict 更轻量。
为什么 dict.fromkeys() 能同时做到去重和保序
Python 3.7+ 中字典正式保证插入顺序,而 dict.fromkeys(iterable) 的行为是:把每个元素作为键依次插入空字典,重复键会被忽略(只保留首次出现),键的顺序就是原列表中首次出现的顺序。最后用 list() 提取键序列,自然得到去重+保序结果。
常见错误现象:list(dict.fromkeys([3, 1, 2, 1])) 返回 [3, 1, 2] —— 这不是 bug,是预期行为;若误以为会按数值大小排序,说明混淆了“插入顺序”和“升序”。
- 该方法要求所有元素必须可哈希(
int、str、tuple等),否则抛出TypeError: unhashable type - 不修改原列表,返回新列表,符合函数式习惯
- 时间复杂度为 O(n),内部使用哈希表查重,远优于
if x not in result的 O(n²) 查找
dict.fromkeys() 和 set() 去重的根本区别
set() 去重后转列表(list(set(lst)))看似简洁,但本质是破坏顺序的:因为 set 不记录插入顺序,且不同 Python 版本、甚至同版本多次运行都可能给出不同排列。这不是“不稳定”,而是设计使然。
使用场景差异:
- 只关心唯一性、完全不依赖顺序 → 用
set(),最快 - 需保留原始出现顺序 → 必须避开
set(),选dict.fromkeys()或显式循环 - 想“去重并排序” → 应分两步:
sorted(dict.fromkeys(lst)),而不是指望set()给你排好
遇到不可哈希元素时怎么办
当列表含 dict、list、set 等不可哈希类型时,dict.fromkeys() 直接报错,此时没有银弹,只能退回到基于逻辑判断的手动方案。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
典型错误示例:dict.fromkeys([{'a': 1}, {'a': 1}, {'b': 2}]) → TypeError。
- 若对象有唯一标识字段(如
'id'),优先用字典推导式:list({item['id']: item for item in lst}.values()) - 若需完全自定义相等逻辑(如忽略大小写、浮点容差),必须用
seen集合 + 循环,但比较逻辑要写在if条件里,不能依赖in - 避免用
[x for i, x in enumerate(lst) if x not in lst[:i]],切片lst[:i]每次都新建子列表,内存和时间开销双高
兼容旧版 Python(
虽然现在主流环境基本都是 3.7+,但如果维护遗留项目,collections.OrderedDict 是明确语义、稳定可用的选择。
代码写法几乎一致:from collections import OrderedDict; list(OrderedDict.fromkeys(lst))。
- 性能略低于
dict.fromkeys()(内存占用更高,构造稍慢) - 在 Python 3.6 及更早版本中是保序去重的**事实标准**
- 不要混用:
OrderedDict.fromkeys()和dict.fromkeys()行为一致,但前者多一层封装,无额外功能增益
真正容易被忽略的是:保序不等于“按某种业务规则排序”,dict.fromkeys() 只忠实地保留第一次出现的位置——哪怕那个位置在数据源里就是错的。校验输入质量,永远比选对去重方法更重要。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










