Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 694
math4tots Avatar asked Dec 21 '12 04:12

math4tots


3 Answers

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.

like image 82
BrenBarn Avatar answered Sep 24 '22 11:09

BrenBarn


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.

like image 25
tom Avatar answered Sep 22 '22 11:09

tom


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

like image 41
Ignacio Vazquez-Abrams Avatar answered Sep 23 '22 11:09

Ignacio Vazquez-Abrams