【发布时间】:2010-01-29 01:02:43
【问题描述】:
我有一个名为 GraphEdge 的类,我希望通过其 tail 和 head 成员在一个集合(内置 set 类型)中唯一定义它,这些成员是通过 __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 和 H 根据我的定义是相同的,因为它们具有不同的哈希值(据我所知,这是集合类型用来确定唯一性的方法),所以它添加了两者都是不同的元素。所以我为GraphEdge 定义了一个相当幼稚的哈希函数,如下所示:
def __hash__( self ):
return hash( self.tail ) ^ hash( self.head )
现在上述工作按预期工作:
>>> 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') 在这种情况下将返回相同的哈希值,所以我希望我不能将 ('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')])
那么集合类型是否使用散列?如果是这样,最后一种情况怎么可能?如果不是,为什么第一个场景(没有定义__hash__)不起作用?我错过了什么吗?
编辑:供未来读者参考,我已经定义了__eq__(也基于tail 和head)。
【问题讨论】: