在Python中给一个类哈希化是个好主意吗?

6
例如,假设我这样做:
>>> class foo(object):
...     pass
... 
>>> class bar(foo):
...     pass
... 
>>> some_dict = { foo : 'foo',
... bar : 'bar'}
>>> 
>>> some_dict[bar]
'bar'
>>> some_dict[foo]
'foo'
>>> hash(bar)
165007700
>>> id(bar)
165007700

根据这个,看起来该类被散列为其id号。因此,不必担心像bar会被哈希成foobar,或者如果我改变了类,哈希值会发生变化。

这种行为可靠吗?还是有什么需要注意的地方?

2个回答

8
是的,任何没有实现__hash__()函数的对象在哈希时都会返回其id。从Python语言参考:数据模型 - 基本定制中可以看到:

用户定义的类默认具有__cmp__()__hash__()方法;使用它们,所有对象都不相等(除了自身),x.__hash__()返回id(x)

然而,如果您想要一个唯一标识符,请使用id以明确您的意图。一个对象的哈希应该是其组成部分的哈希的组合。有关更多详细信息,请参见上面的链接。

2
任何一个类,其元类没有__hash__()函数。 - Ants Aasma
需要注意的是,尽管这是在“Python 2.6有什么新功能”页面中,但这种行为似乎在Python 2.4下也可以正常工作。 - Jason Baker
1
@Jason,我已将引用更改为通用文档。 - Andrew Keeton
1
有一件事情是一个同事补充的:重要的是永远不要持久化使用id的字典。id是对象的内存地址,只在当前进程中有效。 - Jason Baker
1
这个答案已经过时了。 x.__hash__()不再返回id(x) - wim

7

类有默认的__eq____hash__实现,它们使用id()进行比较和计算哈希值。也就是说,它们通过身份来进行比较。实现__hash__方法的主要规则是,如果两个对象相互比较相等,则它们必须具有相同的哈希值。哈希值可以被看作是字典和集合用于更快地查找相等对象的一种优化。因此,如果您更改__eq__以执行不同类型的相等性测试,则还必须更改您的__hash__实现以与该选择一致。

使用身份进行比较的类可以自由地进行变异并用于字典和集合,因为它们的身份永远不会改变。实现__eq__以按值比较并允许其值发生变化的类不能用于哈希集合。


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