如何在python中实现一个好的hash函数

2024-04-25 04:20:29 发布

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

当实现具有多个属性的类(如下面的玩具示例中所示)时,处理散列的最佳方法是什么?

我想__eq____hash__应该是一致的,但是如何实现能够处理所有属性的适当散列函数呢?

class AClass:
  def __init__(self):
      self.a = None
      self.b = None

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

  def __ne__(self, other):
    return not self.__eq__(other)

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

我在this question上读到元组是散列的,所以我想知道上面的例子是否合理。它是?


Tags: and方法函数selfnone示例return属性
3条回答

__hash__应该为相等的对象返回相同的值。它也不应该随着对象的生命周期而改变;通常,您只为不可变对象实现它。

一个简单的实现就是return 0。这总是正确的,但表现不好。

您的解决方案,返回属性元组的散列,是很好的。但是请注意,您不需要列出在元组的__eq__中比较的所有属性。如果某个属性对于不相等的对象通常具有相同的值,请忽略它。不要让散列计算比需要的更昂贵。

编辑:我建议一般不要使用xor来混合散列。当两个不同的属性具有相同的值时,它们将具有相同的散列,而使用xor时,这些属性将彼此取消。元组使用更复杂的计算来混合散列,请参见^{}中的tuplehash

写东西很危险

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

因为如果rhs(即other)对象的计算结果为boolean False,那么它永远不会与任何对象进行比较!

此外,您可能需要再次检查other是否属于AClass的类或子类。如果没有,您将获得异常AttributeError或假阳性(如果另一个类碰巧具有具有匹配值的相同命名属性)。因此,我建议将__eq__重写为:

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

如果您希望进行异常灵活的比较(只要属性按名称匹配,就可以跨不相关的类进行比较),那么您至少应该避免AttributeError,并检查other没有任何其他属性。这取决于具体情况(因为没有标准的方法可以找到对象的所有属性)。

^{}的文档

The only required property is that objects which compare equal have the same hash value; it is advised to somehow mix together (e.g. using exclusive or) the hash values for the components of the object that also play a part in comparison of objects.

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

相关问题 更多 >