重写__hash__后相同哈希值但对象不同

2 投票
2 回答
915 浏览
提问于 2025-04-16 11:46

我在正确地给我的对象生成哈希值时遇到了问题。考虑以下代码:

class Foo:
    def __init__(self, bar):
        self.keys = list(bar.keys())
        self.values = list(bar.values())    
    def __str__(self):
        return ', '.join( '%s: %s' % z for z in zip(self.keys, self.values))    
    def __hash__(self):
        return hash(str(self))

if __name__ == '__main__':
    result = set()
    d = { 1: 2, 3: 4, 5: 6, 7: 8 }
    for i in range(10):
        result.add(Foo(d))
    for r in result:
        print r, hash(r)

我期望结果集中只包含一个元素,因为所有添加的 Foo 对象内容都是一样的,因此它们的哈希值也应该是一样的。

但是,结果却是这样的:

misha@misha-K42Jr:~/Desktop/stackoverflow$ python hashproblem.py 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338

这里的问题是什么呢?哈希值看起来是一样的,那它们不应该被内置的 set 对象当作重复项处理吗?为什么集合中会有重复项呢?

我注意到,如果在往集合中添加元素时使用 str(Foo(d)) 而不是 Foo(d),事情就会按预期工作。为什么会这样呢?

Python 的版本是:

misha@misha-K42Jr:~/Desktop/stackoverflow$ python --version
Python 2.6.6

2 个回答

4

查看这个链接:http://docs.python.org/glossary.html#term-hashable - 你还需要实现 __eq__ 这个方法。

4

因为 __hash__ 方法只是用来处理内部的哈希表,所以你需要同时重新定义 __eq__ 方法。

仅仅重写 __eq__ 方法也是不够的。如果两个对象是相等的,比如说 a.__eq__(b) == True,那么 hash(a)hash(b) 的结果也必须相等。

默认的 __hash__ 方法是:

def __hash__(self):
    return id(self)

撰写回答