2015-04-03 73 views
3

我更熟悉从子类中的超类构建复杂/组合哈希码的“Java方式”。 Python 3中有更好的/不同的/首选的方式吗? (我无法找到通过谷歌这件事具体到Python3什么。)如何在Python3中结合散列码?

class Superclass: 
    def __init__(self, data): 
     self.__data = data 

    def __hash__(self): 
     return hash(self.__data) 

class Subclass(Superclass): 
    def __init__(self, data, more_data): 
     super().__init__(data) 
     self.__more_data = more_data 

    def __hash__(self): 
     # Just a guess... 
     return hash(super()) + 31 * hash(self.__more_data) 

简化这个问题,请假设self.__dataself.__more_data简单,哈希的数据,如strint

回答

3

The python documentation建议您使用XOR到散列结合:

仅有一个要求,就是其比较相等的对象具有相同的哈希值;建议以某种方式混合在一起(例如,使用排他或散列值)用于对象的组成部分,这些组成部分也是对象比较的一部分。

我还建议,因为该上除了XOR和乘法:

注意

hash()截断从对象的自定义__hash__()方法返回到Py_ssize_t大小的值。这通常在64位版本上是8个字节,在32位版本上是4个字节。如果对象的__hash__()必须在不同位大小的版本上互操作,请务必检查所有支持的版本的宽度。一个简单的方法来做到这一点是python -c "import sys; print(sys.hash_info.width)

本文档的Python 2.7和python 3.4一样的,顺便说一句。

+0

伟大的答案。感谢您的参考。回复:“截断” - 这是由于Python的不受限制的整数值? *整数具有无限的精度*(大多数人对Python的学习感到惊讶!) – kevinarpe 2015-04-04 09:17:04

+1

我意识到整数具有无限精度。但是,'hash()'不具有无限精度。它的实现是返回一个最可能为8个字节的“Py_ssize_t”,所以它会返回'__hash__' mod 2^64-1的结果。 – 2015-04-04 09:22:06

+0

这是一个合理的实现:'return super().__ hash __()^ hash(self .__ more_data)'? – kevinarpe 2015-04-04 10:30:30

0

我加入了一个答案,以补充托姆的。

  1. Python整数永远不会溢出;它们扩展为“无限”;它们不像大多数其他语言那样被限制为32位或64位,因此经典模式x + 31 * hash(value)将产生大量整数
  2. Python哈希代码应该是极限编成8个字节(64位)。因此,使用按位异或运算符^来组合散列码更安全。

示例代码阅读:

class Superclass: 
    def __init__(self, data): 
     self.__data = data 

    def __hash__(self): 
     return hash(self.__data) 

class Subclass(Superclass): 
    def __init__(self, data, more_data): 
     super().__init__(data) 
     self.__more_data = more_data 

    def __hash__(self): 
     return super().__hash__()^hash(self.__more_data)