Python __hash__用于等值对象

Bar*_*rry 8 python hash set

假设我有一些Person实体,我想知道一个是否在列表中:

person in people?
Run Code Online (Sandbox Code Playgroud)

我不关心'对象的ID'是什么,只是他们的属性是相同的.所以我把它放在我的基类中:

# value comparison only
def __eq__(self, other):
    return (isinstance(other, self.__class__) and self.__dict__ == other.__dict__)

def __ne__(self, other):
    return not self.__eq__(other)
Run Code Online (Sandbox Code Playgroud)

但是为了能够在集合中测试相等性,我还需要定义哈希所以......

# sets use __hash__ for equality comparison
def __hash__(self):
    return (
        self.PersonID,
        self.FirstName,
        self.LastName,
        self.etc_etc...
    ).__hash__()
Run Code Online (Sandbox Code Playgroud)

问题是我不想列出每个属性,并且我不希望每次属性更改时都修改哈希函数.

这样做可以吗?

# sets use __hash__ for equality comparison
def __hash__(self):
    values = tuple(self.__dict__.values())
    return hash(values)
Run Code Online (Sandbox Code Playgroud)

这是理智的,而不是TOOOO太大的性能损失?在网络应用程序的情况下.

非常感谢.

nne*_*neo 5

字典的无序性质意味着,tuple(self.__dict__.values())如果dicts 的顺序不同(例如,如果一个属性以不同的顺序分配,可能会发生这种情况),很容易产生不同的结果。

因为你values是可哈希的,你可以试试这个:

return hash(frozenset(self.__dict__.iteritems()))
Run Code Online (Sandbox Code Playgroud)

或者,请注意__hash__不需要考虑所有内容,因为__eq__当哈希值比较相等时仍将用于验证相等性。因此,你可能可以逃脱

return hash(self.PersonID)
Run Code Online (Sandbox Code Playgroud)

假设PersonID在实例中相对唯一。

  • 例如,在任何情况下,您都可以愚蠢地从您的哈希函数中“返回 4”;它会影响 set 和 dict 操作的性能(使用您的对象作为键),但不会影响程序的正确性。 (2认同)
  • @keeny:忘记提及:如果您确实希望`PersonID` 为`None`,那么您可以使用像`hash(self.PersonID or self.LastName)` 这样的廉价测试来提高唯一性。这仍然只对一件事进行哈希处理,但是当 `PersonID` 是一个假值(例如 `None`)时会选择 `LastName`。 (2认同)