奇怪的Python集和散列行为是如何工作的?

2024-09-28 03:17:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个名为GraphEdge的类,我希望在一个集(内置的set类型)中通过其tail和{}成员进行唯一定义,这两个成员通过__init__设置。在

如果不定义__hash__,则会看到以下行为:

>>> E = GraphEdge('A', 'B')
>>> H = GraphEdge('A', 'B')
>>> hash(E)
139731804758160
>>> hash(H)
139731804760784
>>> S = set()
>>> S.add(E)
>>> S.add(H)
>>> S
set([('A', 'B'), ('A', 'B')])

集合无法知道E和{}在我的定义中是相同的,因为它们有不同的散列(据我所知,这是集合类型用来确定唯一性的方法),所以它将两者作为不同的元素添加。因此,我为GraphEdge定义了一个相当幼稚的哈希函数,如下所示:

^{pr2}$

现在,上述工作如预期:

>>> E = GraphEdge('A', 'B')
>>> H = GraphEdge('A', 'B')
>>> hash(E)
409150083
>>> hash(H)
409150083
>>> S = set()
>>> S.add(E)
>>> S.add(H)
>>> S
set([('A', 'B')])

但是很明显,在本例中,('A', 'B')和{}将返回相同的哈希值,因此我无法将('B', 'A')添加到已经包含('A', 'B')的集合中。但事实并非如此:

>>> E = GraphEdge('A', 'B')
>>> H = GraphEdge('B', 'A')
>>> hash(E)
409150083
>>> hash(H)
409150083
>>> S = set()
>>> S.add(E)
>>> S.add(H)
>>> S
set([('A', 'B'), ('B', 'A')])

那么set类型是否使用哈希?如果是这样,最后一种情况如何可能?如果不是,为什么第一个场景(没有__hash__定义)不起作用?我错过什么了吗?在

编辑:为了供将来的读者参考,我已经定义了__eq__(也基于tailhead)。在


Tags: 方法函数add元素类型定义init成员
3条回答

你有一个哈希冲突。在哈希冲突中,集合使用==运算符检查它们是否真正相等。在

如果至少需要一个__eq__()和{},则应该始终同时定义它们。如果两个对象的哈希值相等,则执行额外的__eq__()检查以验证唯一性。在

理解hash和==是如何一起工作的很重要,因为这两者都是由集合使用的。对于两个值x和y,重要的规则是:

x == y ==> hash(x) == hash(y)

(x等于y意味着x和y的散列相等)。但是,反之亦然:两个不相等的值可以有相同的哈希值。在

集合(和dicts)将使用哈希来获得相等的近似值,但将使用实数相等运算来判断两个值是否相同。在

相关问题 更多 >

    热门问题