Python中__hash__和__eq__之间的交互

时间:2017-11-28 10:49:44

标签: python-3.x class hash

我写了这个简单的代码,我试图了解究竟发生了什么。我创建了相等的对象,只将其中一个放在字典中。

然后,使用第二个对象作为键,我尝试打印其值的name属性。

由于我的哈希函数,字典返回与我插入的密钥对应的哈希值,对于obj1和obj2是相同的。

这是我的问题:我的哈希函数检查两个对象是否确实相等或者是碰撞的情况吗?

我希望问题很明确。

class Test:

    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        return (isinstance(other, type(self)) and self.name == other.name)


    def __hash__(self):
        return hash(self.name)


obj1 = Test('abc')
obj2 = Test('abc')

d = {}

d[obj1] = obj1

print(d[obj2].name)

1 个答案:

答案 0 :(得分:0)

您可以通过测试几种组合轻松解决这个问题。请考虑以下两种类型:

class AlwaysEqualConstantHash:
    def __eq__(self, other):
        print('AlwaysEqualConstantHash eq')
        return True
    def __hash__(self):
        print('AlwaysEqualConstantHash hash')
        return 4

class NeverEqualConstantHash:
    def __eq__(self, other):
        print('NeverEqualConstantHash eq')
        return False
    def __hash__(self):
        print('NeverEqualConstantHash hash')
        return 4

现在让我们把它放在字典中,看看会发生什么:

>>> d = {}
>>> d[AlwaysEqualConstantHash()] = 'a'
AlwaysEqualConstantHash hash
>>> d[AlwaysEqualConstantHash()]
AlwaysEqualConstantHash hash
AlwaysEqualConstantHash eq
'a'
>>> d[AlwaysEqualConstantHash()] = 'b'
AlwaysEqualConstantHash hash
AlwaysEqualConstantHash eq
>>> d
{<__main__.AlwaysEqualConstantHash object at 0x00000083E8174A90>: 'b'}

如您所见,哈希一直用于处理字典中的元素。一旦在字典中存在具有相同散列的元素,则还进行相等比较以判断现有元素是否等于新元素。因此,由于我们所有新的AlwaysEqualConstantHash对象都与另一个对象相同,所以它们都可以用作字典中的相同键

>>> d = {}
>>> d[NeverEqualConstantHash()] = 'a'
NeverEqualConstantHash hash
>>> d[NeverEqualConstantHash()]
NeverEqualConstantHash hash
NeverEqualConstantHash eq
Traceback (most recent call last):
  File "<pyshell#56>", line 1, in <module>
    d[NeverEqualConstantHash()]
KeyError: <__main__.NeverEqualConstantHash object at 0x00000083E8186BA8>
>>> d[NeverEqualConstantHash()] = 'b'
NeverEqualConstantHash hash
NeverEqualConstantHash eq
>>> d
{<__main__.NeverEqualConstantHash object at 0x00000083E8186F60>: 'a', <__main__.NeverEqualConstantHash object at 0x00000083E8186FD0>: 'b'}

对于NeverEqualConstantHash,这是非常不同的。哈希也一直在使用,但由于新对象永远不会与另一个对象相等,我们无法以这种方式检索现有对象。

>>> x = NeverEqualConstantHash()
>>> d[x] = 'foo'
NeverEqualConstantHash hash
NeverEqualConstantHash eq
NeverEqualConstantHash eq
>>> d[x]
NeverEqualConstantHash hash
NeverEqualConstantHash eq
NeverEqualConstantHash eq
'foo'

如果我们使用完全相同的键,我们仍然可以检索该元素,因为它不需要使用__eq__与自身进行比较。我们还看到如何为具有相同散列的每个现有元素调用__eq__,以便检查这个新对象是否与另一个相等。

所以是的,哈希用于快速将元素排序到字典中。对于被认为相等的元素,哈希必须相等。仅对于与现有元素的哈希冲突,__eq__用于确保两个对象都引用相同的元素。