如何判断对象/实例是否可哈希

时间:2019-05-24 19:44:45

标签: python hash

我最近发现了一个有趣的发现,即某些因素会影响对象/类实例的哈希性。我想知道如何以及为什么?

例如,我有一个名为ListNode的链表类:

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

   def __repr__(self):
        if self.next:
            return "{}->{}".format(self.val, repr(self.next))
        else:
            return "{}".format(self.val)

    # def __eq__(self, other):
        # if not self and not other:
        #     return True
        # elif not self or not other:
        #     return False
        # else:
        #     return self.val == other.val and self.next == other.next

     # def __eq__(self, other):
        # return str(self) == str(other)

注意,我阻止了__eq__方法。 现在,如果我创建一个实例:

A = ListNode(1)
B = ListNode(2)
C = ListNode(3)
A.next = B
B.next = C
print(hash(A))

然后它是可哈希的,但是,每次运行时,我的确得到不同的输出编号。

现在,如果我取消阻止__eq__方法,那么突然该方法将不再可哈希化。为什么?

似乎hash方法将使用__eq__。以及如何知道启用__eq__后不能将其散列?

其他: 如果我编写__eq__方法只是比较两个链表的str版本(第二个__eq__方法),我认为这可以解决问题,因为通过转换链表到string中,它变成可散列的数据,但我仍然收到unhashable错误消息

谢谢!

  

根据@ juanpa.arrivillaga的评论:

__eq__将删除默认的__hash__方法,使其无法散列。 因此,我添加了自己的__hash__方法:

def __hash__(self):
    return hash(id(self))

这解决了问题,并使ListNode在启用__eq__的情况下再次可散列。

1 个答案:

答案 0 :(得分:2)

  

如果一个类没有定义__eq __()方法,它也不应该定义__hash __()操作;如果它定义__eq __()而不是__hash __(),则其实例将不能用作可哈希集合中的项目。

     

(...)

     

重写__eq __()但未定义__hash __()的类会将其__hash __()隐式设置为None。当类的__hash __()方法为None时,该类的实例将在程序尝试检索其哈希值时引发适当的TypeError,并且在检查isinstance(obj,collections.abc.Hashable)时也将被正确标识为不可哈希)。 1

因此__eq __()方法的引入将__hash __()设置为None。您可以添加一个自定义哈希,以允许进行上述构建:

def __hash__(self):
    return self.val

更多信息,请点击此处:https://docs.python.org/3/reference/datamodel.html#object.hash