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

时间:2010-10-23 17:54:24

标签: python hash

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

我想__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上读到元组是可以清洗的,所以我想知道上面的例子是否合情合理。是吗?

3 个答案:

答案 0 :(得分:68)

__hash__应该为相同的对象返回相同的值。它也不应该在对象的生命周期内改变;通常你只为不可变对象实现它。

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

你的解决方案,返回一个属性元组的哈希是好的。但请注意,您不需要列出元组中__eq__中比较的所有属性。如果某些属性对于不等对象通常具有相同的值,则只需将其保留。不要使哈希计算比它需要的更昂贵。

编辑:我建议不要使用xor来混合哈希。当两个不同的属性具有相同的值时,它们将具有相同的散列,并且对于xor,这些将取消彼此。元组使用更复杂的计算来混合哈希,请参阅tupleobject.c中的tuplehash

答案 1 :(得分:12)

是危险的
def __eq__(self, other):
  return other and self.a == other.a and self.b == other.b

因为如果你的rhs(即other)对象的计算结果为布尔值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不是没有任何其他属性。你如何做到这取决于具体情况(因为没有标准的方法来查找对象的所有属性)。

答案 2 :(得分:11)

object.__hash__(self)

的文档
  

唯一需要的属性是比较相等的对象具有相同的哈希值;建议以某种方式将对象组件的哈希值混合在一起(例如使用exclusive或),这些哈希值也是对象比较中的一部分。

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