如何为含多个可比较属性的Python对象实现__hash__方法
核心问题:你当前的相等逻辑不符合等价关系要求
Python 中__eq__定义的相等关系必须是等价关系,满足三个基本条件:
- 自反性:
x == x恒为真 - 对称性:如果
x == y那么y == x - 传递性:如果
x == y且y == z,那么x == z
你现在设计的「a相等或b相等就视为相等」的逻辑不满足传递性,举个简单的例子:
t1 = Transaction(1, 2) t2 = Transaction(1, 3) t3 = Transaction(4, 3)
按照你的逻辑t1 == t2(a属性相等)、t2 == t3(b属性相等),但t1和t3的a、b都不相等,明显不满足传递性,这种情况下你不可能写出符合「相等对象哈希必须一致」约定的__hash__方法。
正确的实现方案
你想要的效果是:只要新交易的a在历史交易中出现过,或者b在历史交易中出现过,就拒绝插入。这种场景不要靠修改类的__eq__和__hash__实现,单独维护两个去重集合即可:
seen_a = set() seen_b = set() transactions = [] # 或者用set存,按需选择 def add_transaction(t: Transaction) -> bool: if t.a in seen_a or t.b in seen_b: return False # 重复,插入失败 seen_a.add(t.a) seen_b.add(t.b) transactions.append(t) return True
这个方案逻辑清晰,性能也能保证O(1)的插入判断效率,完全满足你的需求。
不推荐的硬实现方式
如果非要强行写__hash__满足约定,你只能让所有Transaction对象返回同一个固定哈希值:
def __hash__(self): return 0
但这么做的后果是set插入的时间复杂度会直接退化成O(n),每次插入都要和已有的所有元素调用__eq__比较,而且因为相等逻辑不满足传递性,还是会出现不符合预期的去重结果,完全不推荐在生产环境使用。
内容的提问来源于stack exchange,提问作者Yogesh G
相关产品推荐
相关产品推荐

