如何为具有多个可比属性的对象实现__hash__方法

4
我有一个名为Transaction的类,它包含多个属性。如果这些属性中有任何一个匹配,则我希望将这些事务视为重复事务,并且不想在集合中存储重复项。
class Transaction:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __eq__(self, other):
        if not isinstance(other, Transaction):
            return NotImplemented
        return self.a == other.a or self.b == other.b

    def __hash__(self):
        # TODO

我了解到,如果我们想要在将元素插入集合时避免重复,实现__eq____hash__都很重要。此外,如果A == B,则它们的哈希值也应该符合契约。

在这种情况下,我如何实现__hash__,以便在尝试将事务插入集合时,如果它包含属性'a'或'b'的重复值,则被拒绝。

提前感谢!


2
我感觉有一个好的简单方法可以做到这一点,但是就是想不出来 :) 对这个票据很感兴趣 :) - Ben
你的意思是如果同一对象上的ab都相同,那么它被视为重复吗? - gold_cy
@gold_cy 不,它们的意思是如果ab中有任一一个相同,则被视为相等 - juanpa.arrivillaga
如果self.a == other.a或者self.b == other.b,那么self和other应该被视为相等。 - Yogesh Kumar Gupta
1
相等应该是可传递的(x == y and y == z => x == z)。但是根据你的定义,这并不是这种情况,因为你可以有 x.a == y.a and y.b == z.b,但是 z.a != x.a and z.b != x.b - njzk2
显示剩余3条评论
2个回答

1
我不确定是否可能将这样的or条件压缩成单个哈希值。我尝试使用德摩根定律(not nand代替or)进行实验,但没有结果。
让类型可哈希的最佳选择可能是返回一个常量值(使得所有实例都具有相同的哈希值),并依赖于散列表的冲突行为。
这在标准中是隐含允许的,因为规则是

a == b 意味着 hash(a) == hash(b)

而不是

hash(a) == hash(b) 意味着 a == b

这从来不是个问题(毕竟,哈希碰撞偶尔会发生——哈希只有32或64位)

一个集合将通过其自然的避免碰撞行为来适应这种行为,虽然这样做的性能不佳,但至少可以让你使用set数据结构。

>>> class A:
...   def __init__(self, prop):
...     self.prop = prop
...   def __repr__(self):
...     return f'A({self.prop})'
...   def __eq__(self, other):
...     return self.prop == other.prop
...   def __hash__(self):
...     return 0
... 
>>> {A(1), A(2), A(3), A(1)}
{A(1), A(2), A(3)}

诚然,这有点违背使用set的初衷,但如果您将您的对象用作dict中的键,则可能会更有意义。


2
如果我们为所有对象保持相同的哈希值,那么使用集合或列表并不会有太大区别。在这种情况下,两者的性能几乎相同。例如,我可以检查列表中是否存在元素(这将调用__eq__方法),如果不存在,则将其添加到列表中。 - Yogesh Kumar Gupta

0

我认为这是不可能的,你也不应该这样做。无论你在__eq__中使用什么,都应该在__hash__中存在,否则:

假设你只在__hash__中使用了a的哈希值,你最终会得到这样一种情况:两个相等的对象具有不同的哈希值(因为它们的b相等),这与实际规则相矛盾:

if obj1 == obj2 -> True then hash(obj1) == hash(obj2) "must" be True

__hash__ 中只使用 b 也是一样的。


1
我完全理解这个问题,我的目标是实现它。请问有没有一种方法可以在保持合同的情况下实现它呢? - Yogesh Kumar Gupta
@YogeshKumarGupta 嗯,我想说没有办法。让我们等待其他回复。 - S.B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接