必须同时重写__hash__和__eq__且保持一致性:相等对象哈希值必须相同,否则字典查找不到键或出现重复;推荐用hash((self.x, self.y))实现,避免引用可变属性。

为什么重写 __hash__ 和 __eq__ 后对象才能当字典键
Python 字典(以及 set)依赖哈希值快速定位键,但仅靠 __hash__ 不够:如果两个对象 __hash__ 相同,Python 会进一步调用 __eq__ 判断是否真为同一键。若没重写 __eq__,默认用 is(内存地址)比较,导致逻辑相等的对象被当成不同键;若只重写 __eq__ 不重写 __hash__,对象会自动变为不可哈希(TypeError: unhashable type),根本进不了字典。
必须同时重写且保持一致性
这是最容易踩的坑:只要重写了 __eq__,就必须重写 __hash__,且要保证「相等的对象必须有相同哈希值」。否则字典行为未定义——可能查不到已存的键,或出现重复键。
- 若对象逻辑上相等(比如两个
Point(x=1, y=2)),__eq__应返回True,__hash__必须返回相同整数 - 推荐用
hash((self.x, self.y))这类元组哈希,它自动处理不可变成员的组合哈希 - 切勿在
__hash__中引用可变属性(如列表、字典),否则哈希值会变,键就丢了 - 一旦对象放入字典后修改了影响
__eq__/__hash__的字段,该键将无法再被访问或删除
一个安全、可复用的实现模板
以下是最小可行写法,适用于大多数不可变或逻辑上应视为不可变的类:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
if not isinstance(other, Point):
return False
return self.x == other.x and self.y == other.y
def __hash__(self):
return hash((self.x, self.y))
关键点:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
立即学习“Python免费学习笔记(深入)”;
-
isinstance检查避免和无关类型比较时抛异常 - 用元组
(self.x, self.y)构造哈希,简洁且符合 Python 惯例 - 不加
__slots__也能工作,但加上能防止意外赋值(比如p.z = 3),进一步保障哈希稳定性
常见错误现象与调试提示
遇到这些表现,基本就是 __hash__/__eq__ 没写对:
-
TypeError: unhashable type: 'Point'→ 忘了定义__hash__,或显式设为None(如__hash__ = None) - 字典里明明存了
Point(1, 2),却查不到:__eq__返回False(比如漏了isinstance检查,导致和tuple比较时直接报错或返回False) - 两个看似相同的对象在
set里共存:__hash__实现不一致(比如用了id(self)或随机数) - 修改对象字段后,原字典键“消失”:
__hash__依赖了可变状态,或对象本就不该被修改
真正麻烦的不是写法,而是让团队其他人在后续维护时意识到这个类是“按值哈希”的——文档注释和字段命名(比如用 name 而非 _name_cache)比代码本身更影响长期可靠性。

















