在Python对象中,哪个是更高效的__hash__实现?散列自身__str__,一个属性元组,或者一个真正的散列例程



为任何给定的Python对象创建库存__hash__()的一种常见而快速的方法似乎是到return hash(str(self)),如果该对象实现__str__()的话。不过,这有效吗?根据这个SO答案,对象属性元组的散列是"好的",但似乎并不能表明它是否是Python最有效的。还是最好为每个对象实现一个__hash__(),并使用该页面中的真实哈希算法,将各个属性的值混合到__hash__()返回的最终值中?

假设我已经实现了这个SO问题中的Jenkins散列例程。哪个__hash__()更适合使用?:

# hash str(self)
def __hash__(self):
    return hash(str(self))
# hash of tuple of attributes
def __hash__(self):
    return hash((self.attr1, self.attr2, self.attr3,
                 self.attr4, self.attr5, self.attr6))
# jenkins hash
def __hash__(self):
    from jenkins import mix, final
    a = self.attr1
    b = self.attr2
    c = self.attr3
    a, b, c = mix(a, b, c)
    a += self.attr4
    b += self.attr5
    c += self.attr6
    a, b, c = final(a, b, c)
    return c


为了简单起见,假设示例对象中的属性都是整数。还假设所有对象都派生自基类,并且每个对象实现自己的__str__()。使用第一个散列的代价是,我也可以在基类中实现它,而不向每个派生对象添加额外的代码。但是,如果第二个或第三个__hash__()实现在某种程度上更好,这是否会抵消为每个派生对象添加代码的成本(因为每个派生对象可能具有不同的属性(?



编辑:第三个__hash__()实现中的import之所以存在,只是因为我不想起草整个示例模块+对象。假设import确实发生在模块的顶部,而不是每次调用函数时。



结论:根据这个封闭SO问题的答案和评论,我似乎真的想要元组哈希实现,不是为了速度或效率,而是因为__hash____eq__的潜在对偶性。由于哈希值将具有某种形式的有限范围(例如,可以是32位或64位(,因此在发生哈希冲突的情况下,将检查对象相等性。因此,由于我确实通过使用自身/他人属性的元组比较来实现每个对象的__eq__(),所以我也想使用属性元组来实现__hash__(),这样我就尊重事物的散列/相等性。

您的第二个函数有一个重要的性能问题:每次调用函数时都要导入两个名称。当然,它相对于字符串哈希版本的性能取决于字符串的生成方式。

也就是说,当你有定义对象相等的属性,而这些属性本身就是可散列类型时,最简单(几乎可以肯定是性能最好(的方法是散列包含这些属性值的元组。

def __hash__(self):
    return hash((self.attr1, self.attr2, self.attr3))

最新更新