math4tots
math4tots

Reputation: 8870

python dictionary conundrum

On the console I typed in

>>> 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'>

I thought at first that the reason that d only kept one pair was because hash(a) and hash(b) returned the same values, so I tried:

>>> 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>}

Now I'm confused. How come in the first code listing, d only kept one pair, but in the second listing d both keys were kept despite having same hash?

Upvotes: 7

Views: 148

Answers (4)

tom
tom

Reputation: 19153

The hash does not determine the unique key in a dictionary. In some ways, hash functions are an "implementation detail", in that they determine how the dictionary internally stores its entries. a == b implies hash(a) == hash(b), but the converse does not hold in general. Two keys also need to be equal to each other (when applying the == operator) to be treated as equivalent keys in a dictionary.

Upvotes: 4

SidJ
SidJ

Reputation: 677

The keys are different for the first and second objects. As they are objects the key is some readable equivalent of the object not a string.

Upvotes: 0

BrenBarn
BrenBarn

Reputation: 251383

The two objects in your original example were collapsed not because they have the same hash, but because they compare equal. Dict keys are unique with respect to equality, not hash. Python requires that any two objects that compare equal must have the same hash (but not necessarily the reverse).

In your first example, the two objects are equal, since they both have the str equality behavior. Since the two objects compare equal, they are collapsed to one. In the second example, they don't compare equal. By default user-defined classes use identity for equality --- that is, each object compares equal only to itself. So your two objects are not equal. It doesn't matter than they have the same hash.

Upvotes: 8

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798626

If you want a type to be hashable then you must also define __eq__(). str defines __eq__() properly, but A and B do not.

Upvotes: 2

Related Questions