Python - 类__hash__方法和集合

时间:2016-07-18 06:54:48

标签: python python-3.x hash set python-datamodel

我正在使用set()类的__hash__python方法来阻止在set中添加相同的哈希对象。根据{{​​3}},set()将相同的哈希对象视为同一个对象,只需添加一次即可。

但它的行为如下:

class MyClass(object):

    def __hash__(self):
        return 0

result = set()
result.add(MyClass())
result.add(MyClass())

print(len(result)) # len = 2

如果是字符串值,它可以正常工作。

result.add('aida')
result.add('aida')

print(len(result)) # len = 1

我的问题是:为什么相同的哈希对象在集合中不相同?

2 个答案:

答案 0 :(得分:16)

您的阅读不正确。 __eq__方法用于等式检查。文档只是声明__hash__ ab a == b的{​​{1}} a.__eq__(b)的{​​{1}}值必须相同。< / p>

这是一个常见的逻辑错误:a == b为真 implies hash(a) == hash(b)也是如此。但是,暗示并不一定意味着 equivalence ,除了先验之外,hash(a) == hash(b)意味着a == b

要使MyClass的所有实例相互比较相等,您需要为它们提供__eq__方法;否则Python将比较他们的身份。这可能会:

class MyClass(object):
    def __hash__(self):
        return 0
    def __eq__(self, other):
        # another object is equal to self, iff 
        # it is an instance of MyClass
        return isinstance(other, MyClass)

现在:

>>> result = set()
>>> result.add(MyClass())
>>> result.add(MyClass())
1

实际上,您将__hash__基于对象的用于__eq__比较的属性,例如:

class Person
    def __init__(self, name, ssn):
        self.name = name
        self.ssn = ssn

    def __eq__(self, other):
        return isinstance(other, Person) and self.ssn == other.ssn

    def __hash__(self):
        # use the hashcode of self.ssn since that is used
        # for equality checks as well
        return hash(self.ssn)

p = Person('Foo Bar', 123456789)
q = Person('Fake Name', 123456789)
print(len({p, q})  # 1

答案 1 :(得分:5)

设置需要两个方法来使对象具有可清除性:__hash____eq__。当两个实例必须在被认为相等时返回相同的哈希值。如果集合中存在散列且该实例被认为等于集合中具有相同散列的实例之一,则认为实例已存在于集合中。

您的课程没有实现__eq__,因此使用默认的object.__eq__,只有在obj1 is obj2也为真时才会返回true。换句话说,如果两个实例完全相同的实例,则它们仅被视为相等。

仅仅因为他们的哈希匹配,就一组而言,它们并不是唯一的;即使具有不同哈希值的对象也可以在同一个哈希表槽中结束,因为使用了针对表大小的哈希的模数

添加一个自定义__eq__方法,当两个实例相等时返回True

def __eq__(self, other):
    if not isinstance(other, type(self)):
        return False
    # all instances of this class are considered equal to one another
    return True