# hashkey/digest for a complex object

Arnaud Delobelle arnodel at gmail.com
Sun Oct 10 12:06:00 CEST 2010

```Steven D'Aprano <steve at REMOVE-THIS-cybersource.com.au> writes:

> On Sat, 09 Oct 2010 21:39:51 +0100, Arnaud Delobelle wrote:
>
>> 1. hash() is an idempotent function, i.e. hash(hash(x)) == hash(x) hold
>> for any hashable x (this is a simple consequence of the fact that
>> hash(x) == x for any int x (by 'int' I mean 2.X int)).
>
> It's a beautiful theory, but, alas, it is not the case.
>
>>>> hash(-1) == -1
> False
>>>> hash(2**64) == 2**64
> False
>
> to give only two of an infinite number of counter-examples.

I can only see one counterexample, (-1).  2**64 is of type 'long' in 2.X
on your machine (or, to be pedantic, 2.x where x >= 2).  And, in fact,
(-1) is the only int such that hash(x) != x.

In can only guess that (-1) is a value that has a special meaning when
hashing.  Try this (Python 2.6):

>>> class A(object):
...     def __hash__(self): return -1
...
>>> a = A()
>>> hash(a)
-2

> Aside: what do you mean by '2.x int'? Do you mean an int in 2.x versions
> before, or after, ints and longs were partially integrated?

Either.

> [steve at sylar ~]\$ python2.1
> Python 2.1.3 (#1, Aug 12 2010, 01:53:57)
> [GCC 4.1.2 20070925 (Red Hat 4.1.2-27)] on linux2
>>>> 2**64
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> OverflowError: integer exponentiation
>>>>
>
>
> People keep forgetting that 2.2 introduced nearly as many far-reaching
> changes as 3.0.

I didn't forget, but what bearing does it have on this particular issue?

```