我使用python类的set()__hash__方法来防止在集合中添加相同的哈希对象.根据python data-model document, 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

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

推荐答案

你的读数不正确.__eq__方法用于相等性判断.文件只是说明,对于a == b(即a.__eq__(b))为真的两个对象ab__hash__值也必须相同.

这是一个常见的逻辑错误:a == b为真100 hash(a) == hash(b)也为真.然而,暗示不一定意味着101,即除了先前的hash(a) == hash(b),还意味着a == b.

要使MyClass的所有实例彼此相等,需要为它们提供__eq__方法;否则Python将比较它们的identities instead.这可能会:

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

Python-3.x相关问答推荐

是否可以使用参数对Flask重定向?

切片时是否在NumPy ND数组中创建新对象?

我没有';无法理解此TemplateDoesNotExist错误

在 Python 中比较和排序列之间的值(带有不匹配列)

如何使用python将pdf文件的页面合并为单个垂直组合页面

替换 .txt 文件中的项目列表

PyTest:尽管明确运行了测试,但是被标记为没有运行测试

如果集合大于 len(x),则 pandas 在重复的行中拆分集合列

无法提出给定 for 循环的原因 (Python 3.11)

asyncio.as_completed() 应该接受 `Iterable`,但如果输入是 `Generator` 就会崩溃?

Pandas 在每组两个条件之间获得时间增量

!date 的命令无法从 jupyter notebook 运行

位对的距离

为列表列表中的每个列表插入 str 到 index[0] 中. Python

如何在python中将列表转换为其他格式

判断是否存在大文件而不下载它

Python从base64转换为二进制

Python:pprint的模块错误,打印没有错误

在 linux mint 上安装 python3-venv 模块

TypeError:无法实例化类型元组;使用 tuple() 代替