字典的key不能是列表,因为列表是可变对象,不可哈希,执行hash([1,2])会直接抛出TypeError;而字典依赖哈希值快速查找,若键可变会导致哈希表失效。
为什么字典的 key 不能是列表
因为 dict 内部依赖哈希值做快速查找,而列表是可变对象,hash([]) 会直接抛出 TypeError: unhashable type: 'list'。只要对象在插入后可能被修改(比如调用 .append() 或 .pop()),Python 就禁止它当 key —— 否则哈希表结构会失效。
元组为什么能当 key
元组是不可变的,且所有元素也必须是可哈希的,才能整体可哈希。这意味着 (1, "a", True) 可以作 key,但 (1, ["x"], 2) 不行,因为内层列表不可哈希。
- 嵌套元组可以:
((1, 2), ("a", "b"))是合法 key - 单元素元组别漏逗号:
(42,)✅,(42)❌(那是 int) - 空元组
()是合法 key,常用于无参数的缓存标识
实际替换操作:从 list → tuple 的常见场景
典型需求是把「坐标」「配置组合」「多字段标识」转成 dict key。比如你想按 (x, y) 缓存计算结果:
# 错误写法(运行即报错)
cache = {}
point = [10, 20]
cache[point] = "result" # TypeError!
正确写法
cache = {}
point = (10, 20) # 注意:不是 list,是 tuple
cache[point] = "result"
print(cache[(10, 20)]) # 输出 "result"
如果原始数据是 list,记得显式转换:cache[tuple(my_list)] = value。但要注意:若 my_list 包含不可哈希项(如另一 list),这步仍会失败。
容易踩的坑:看似 tuple,实则不可哈希
最隐蔽的问题是元组里混入了不可哈希对象。例如:
-
({"a": 1}, "b")→ 字典不可哈希 -
([1, 2], "c")→ 列表不可哈希 -
(set([1]), "d")→ set 不可哈希
调试时可快速验证:hash(obj) 不报错才安全。另外,numpy 数组、pandas Series 默认也不可哈希,即使它们“看起来像”元组内容 —— 它们得先转成 Python 原生 tuple + 基础类型才行。
真正麻烦的不是怎么换,而是换完之后忘了检查嵌套结构是否全可哈希。