Python 中 __hash__ 和 __eq__ 的契约
Python 中 __hash__ 和 __eq__ 方法之间有什么契约关系?如果重写其中一个,为什么通常需要重写另一个?
回答
Yahuda
契约:
- 如果
a == b为 True,则hash(a) == hash(b)必须为 True - 反之不一定:
hash(a) == hash(b)不要求a == b(哈希碰撞) - 可变对象不应该实现
__hash__(或设为 None)
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if not isinstance(other, Person):
return NotImplemented
return self.name == other.name and self.age == other.age
def __hash__(self):
return hash((self.name, self.age))
p1 = Person('Alice', 30)
p2 = Person('Alice', 30)
print(p1 == p2) # True
print(hash(p1) == hash(p2)) # True(如果 __hash__ 正确实现)
后果:
- 只重写
__eq__不重写__hash__-> 对象不可哈希(__hash__设为 None) - 可变对象定义了
__hash__-> 作为 dict key 后修改属性可能导致无法查找 - 应该使用不可变字段(如 tuple)计算哈希值