dict.fromkeys()能去重且保序是因为Python 3.7+中字典保持插入顺序,且键唯一,构造时重复key被覆盖但首次位置保留;仅适用于可哈希元素,不可哈希时需手动遍历加标识去重。

为什么 dict.fromkeys() 能去重且保序
Python 3.7+ 中,dict 保证插入顺序,而 dict.fromkeys(iterable, value) 会按迭代顺序把每个元素作为 key 插入字典——重复的 key 会被自动覆盖,但首次出现的位置被保留。所以 list(dict.fromkeys(seq)) 实际上是利用字典 key 的唯一性和有序性完成去重保序。
注意:这不是“借用 dict 的去重能力”,而是依赖其构造过程中的键插入行为;value 参数(默认为 None)完全无关紧要,只占位。
dict.fromkeys() 去重的实操限制
它只适用于可哈希(hashable)元素。一旦列表含 list、dict、set 等不可哈希类型,会直接抛出 TypeError: unhashable type。
- ✅ 支持:
int、str、tuple(且内部元素也需可哈希)、None - ❌ 不支持:
[1, 2]、{"a": 1}、{1, 2}、set() - ⚠️ 注意:
(1, [2])看似是 tuple,但因含 list 而不可哈希
替代方案:遇到不可哈希元素怎么办
没法用 dict.fromkeys() 时,得退回到手动遍历 + 成员检查。虽然慢(O(n²)),但通用:
创建 Flask + Vue.js 全栈项目,采用单端口架构、uv 依赖管理、结构化日志和生产级前端设计。当用户要求以下操作时触发:创建新的 Flask+Vue 项目、搭建 Web 应用、构建全栈 Python+Vue 应用、初始化 Flask Web 项目、设置单端口 Flask 前后端项目。触发词:新建项目、创建项目、搭建项目、Flask项目、Vue项目。
立即学习“Python免费学习笔记(深入)”;
seen = set()
result = []
for item in seq:
# 把不可哈希对象转成可哈希标识(如 JSON 字符串),或用 id()(仅限临时内存对象)
marker = str(item) # 简单但有风险:[1,2] 和 [1, 2] 字符串相同,但 [1,"2"] 和 [1,2] 可能撞
if marker not in seen:
seen.add(marker)
result.append(item)
更稳妥的做法是用 json.dumps(item, sort_keys=True)(要求所有内容可 JSON 序列化),或自定义哈希逻辑(比如对 list 元素逐个比对)——但性能代价明显上升。
性能与兼容性提醒
dict.fromkeys() 是目前 CPython 下最快的标准保序去重方法,比 collections.OrderedDict.fromkeys()(3.7 前常用)快,也比手写循环简洁。但它在 PyPy 或旧版 Python(
- Python 3.6(CPython):巧合保序,但属实现细节,不应依赖
- Python 3.7+:语言规范保证 dict 有序,可放心用
- PyPy / Jython:查对应版本文档,不要假设行为一致
真正容易被忽略的是:空列表、None、布尔值这些“看起来像假值”的元素,在去重中不会被误删——dict.fromkeys() 只看相等性,不看真假性。

















