python字典键必须是可哈希类型,即对象生命周期内哈希值不变且实现__hash__()和__eq__()方法;常见可哈希类型包括int、str、tuple(元素全可哈希)、frozenset、none及合规自定义类;list、dict、set等不可变性或未实现哈希协议的类型不可用作键。

Python字典的键必须是可哈希(hashable)类型,本质要求是:对象在生命周期内其哈希值不可变,且支持 __hash__() 和 __eq__() 方法。不可变类型通常可哈希,但不是绝对——关键看是否真正满足哈希协议。
常见的可哈希类型(可直接作字典键)
以下类型默认实现哈希协议,且内容不可变,安全用作键:
-
数字类型:
int、float、complex、bool(True/False是int的子类) -
字符串:
str,如"name"、"2024" -
元组:
tuple,但仅当其**所有元素都可哈希**时才可哈希,例如(1, "a")✅,而(1, [2, 3])❌(含列表) -
frozenset:冻结的集合,如
frozenset({1, 2})✅;普通set不可哈希 ❌ - None:单例对象,可哈希
-
自定义类实例:若显式定义了
__hash__且不定义__mutate__类行为(或设为__hash__ = None表示不可哈希),同时保证逻辑相等的对象哈希值一致
典型的不可哈希类型(不能作字典键)
这些类型因可变性或未实现哈希协议,直接用作键会触发 TypeError: unhashable type:
-
列表(list):可原地修改,如
[1, 2] -
字典(dict):本身是可变容器,如
{"a": 1} -
集合(set):可添加/删除元素,如
{1, 2} -
字节数组(bytearray):可变,区别于不可变的
bytes -
大多数自定义类的默认实例:除非明确定义
__hash__方法,否则默认继承自object,且若定义了__eq__但没定义__hash__,Python 会自动将__hash__设为None
如何判断一个对象是否可哈希?
最直接的方式是调用内置函数 hash():
本文档主要讲述的是Python开发网站指南;HTML是网络的通用语言,一种简单、通用的全置标记语言。它允许网页制作人建立文本与图片相结合的复杂页面,这些页面可以被网上任何其他人浏览到,无论使用的是什么类型的电脑或浏览器 Python和其他程序语言一样,有自身的一套流程控制语句,而且这些语句的语法和其它程序语言类似,都有for, if ,while 类的关键字来表达程序流程。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
立即学习“Python免费学习笔记(深入)”;
- 能成功返回整数 → 可哈希,例如
hash("hello")、hash((1, 2)) - 抛出
TypeError→ 不可哈希,例如hash([1, 2])、hash({"a": 1})
注意:hash() 成功只是必要条件,不是充分条件——还需确保自定义类中 __hash__ 与 __eq__ 逻辑一致(即:若 a == b,则必须有 hash(a) == hash(b))。
小技巧:把不可哈希对象“转成”可哈希形式
有时需要以列表、字典等内容为逻辑键,可通过转换规避限制:
- 列表 → 元组:
d[tuple(my_list)] = value(前提是列表元素都可哈希) - 字典 → 排序后的 frozenset of items:
frozenset(d.items())(适用于键值都可哈希且无序比较场景) - 嵌套结构 → JSON 字符串(需确保内容可序列化):
json.dumps(obj, sort_keys=True) - 自定义对象 → 实现
__hash__,例如基于只读属性元组:def __hash__(self): return hash((self.id, self.name))









