将自定义__eq__类作为哈希值的比较

Class Custom __eq__ as Comparison of Hashes

提问人:localusername 提问时间:3/1/2019 最后编辑:Aran-Feylocalusername 更新时间:3/1/2019 访问量:154

问:

考虑一个自定义类:

class MyObject:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __hash__(self):
        return hash((self.a, self.b))

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__hash__() == other.__hash__()

让相等依赖于哈希值是一个坏主意吗?这似乎是一种更优雅、更易读的机制,而不是以零碎的方式检查每对属性以获得更多的属性。

self.a == other.a and self.b == other.b and ... self.n == other.n

或者使用 getattr 和列表进行更动态的检查(有没有更好的方法来比较大量属性对?

内置哈希函数返回的哈希大小是否不够大,无法在相对较大的数据集中可靠?

Python 哈希 相等

评论

1赞 Aran-Fey 3/1/2019
尝试。MyObject(-1, 0) == MyObject(-2, 0)

答:

3赞 Martijn Pieters 3/1/2019 #1

是的,这是个坏主意。哈希值不是唯一的,具有相等哈希值的对象也不能保证实际上也是相等的:

>>> (-1, 0) == (-2, 0)
False
>>> hash((-1, 0)) == hash((-2, 0))
True

哈希并不意味着是唯一的;它们是一种在有限大小的哈希表中快速选择槽的方法,便于查找 O(1) 字典,并且允许和预期发生冲突。

是的,Python 要求相等的对象应该具有相等的哈希值,但这并不意味着这种关系可以逆转。

我只是比较元组:

def __eq__(self, other):
    return (self.a, self.b) == (other.a, other.b)

如果您要编写大量数据类,则都需要相等性测试和散列的简单等,请使用 dataclasses 模块(Python 3.7 或更高版本,或使用向后移植):

from dataclasses import dataclass

@dataclass(frozen=True)
class MyObject:
    a: int
    b: int

上面的类现在带有一个 and 方法:__hash____equals__

>>> MyObject(-1, 0) == MyObject(-2, 0)
False
>>> hash(MyObject(-1, 0)) == hash(MyObject(-2, 0))
True
>>> MyObject(42, 12345) == MyObject(42, 12345)
True

评论

0赞 Aran-Fey 3/1/2019
你说你比较元组,但有什么理由不这样做吗?return vars(self) == vars(other)
1赞 Martijn Pieters 3/1/2019
@Aran-Fey:我更喜欢直言不讳; 在对象上存储一些附加属性(例如,不同用例的注释)时中断。 打破平等测试将是非常令人惊讶的。vars(self) == vars(other)obj._cache_key = 'foobar'