3

__hash__()为任何给定的 Python 对象创建股票的一种常见且快速的方法似乎是return hash(str(self)),如果该对象实现了__str__(). 但是,这有效吗?根据这个 SO answer,对象属性元组的哈希是“好”的,但似乎并不表明它是否对 Python 最有效。还是__hash__()为每个对象实现一个并使用此页面中的真正散列算法并将各个属性的值混合到由返回的最终值中 会更好__hash__()吗?

假装我已经从这个 SO question实现了 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__()实现在某些方面更好,这是否抵消了为每个派生对象添加代码的成本(因为每个派生对象可能具有不同的属性)?



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



结论:根据对这个封闭的 SO 问题的回答和评论,看起来我真的想要元组哈希实现,不是为了速度或效率,而是因为 and 的底层二元__hash____eq__。由于散列值将具有某种形式的有限范围(例如,32 位或 64 位),如果确实发生散列冲突,则会检查对象相等性。因此,由于我确实__eq__()通过使用自我/其他属性的元组比较来实现每个对象,所以我还想__hash__()使用属性元组来实现,以便尊重事物的哈希/相等性质。

4

1 回答 1

3

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

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

def __hash__(self):
    return hash((self.attr1, self.attr2, self.attr3))
于 2013-01-18T00:42:25.710 回答