在我输入的控制台上
>>> class S(str): pass
...
>>> a = 'hello'
>>> b = S('hello')
>>> d = {a:a, b:b}
>>> d
{'hello': 'hello'}
>>> type(d[a])
<class '__main__.S'>
>>> type(d[b])
<class '__main__.S'>
我首先想到d
只保留一对的原因是因为hash(a)
和hash(b)
返回了相同的值,所以我尝试了:
>>> class A(object):
... def __hash__(self):
... return 0
...
>>> class B(object):
... def __hash__(self):
... return 0
...
>>> d = {A():A(),B():B()}
>>> d
{<__main__.A object at 0x101808b90>: <__main__.A object at 0x101808b10>, <__main__.B object at 0x101808d10>: <__main__.B object at 0x101808cd0>}
现在我很困惑。
如何在第一个代码清单中d
只保留一对,但在第二个清单d
中,尽管有相同的哈希,但两个密钥都被保留了?
答案 0 :(得分:8)
原始示例中的两个对象是折叠的,不是因为它们具有相同的哈希值,而是因为它们相等。 Dict键在相等方面是唯一的,而不是哈希。 Python要求任何两个比较相等的对象必须具有相同的哈希值(但不一定相反)。
在第一个示例中,两个对象是相等的,因为它们都具有str
相等行为。由于两个对象比较相等,因此它们折叠为一个。在第二个例子中,他们不比较平等。默认情况下,用户定义的类使用identity来实现相等性 - 也就是说,每个对象只与自身进行比较。所以你的两个对象并不相同。它们具有相同的哈希并不重要。
答案 1 :(得分:4)
哈希不确定字典中的唯一键。在某些方面,散列函数是“实现细节”,因为它们确定字典在内部如何存储其条目。 a == b表示hash(a)== hash(b),但反过来并不成立。两个键也需要彼此相等(当应用==运算符时)被视为字典中的等效键。
答案 2 :(得分:2)
如果您希望类型为hashable,请you must also define __eq__()
。 str
正确定义__eq__()
,但A
和B
没有。
答案 3 :(得分:0)
第一个和第二个对象的键不同。因为它们是对象,所以键是对象的可读等效物而不是字符串。