Skip to content

New snippet: hash(-1) #366

Description

@ericbn

Description

Small integers hash to themselves, except -1.

Snippet preview

>>> for i in range(-4, 4):
...     print(i, hash(i))
...
-4 -4
-3 -3
-2 -2
-1 -2
0 0
1 1
2 2
3 3

Explanation

See https://omairmajid.com/posts/2021-07-16-why-is-hash-in-python/ and https://www.reddit.com/r/Python/comments/oks5km/comment/h5a7ylc/

It's explained by u/ExoticMandibles on Reddit:

The reference implementation of Python is "CPython", which is almost certainly the Python you're using. CPython is written in C, and unlike Python, C doesn't have exceptions. So, in C, when you design a function, and you want your function to be able to indicate "there was an error", it has to return that error as its return value.

The hash() function in CPython can return an error, so it defines a return code of -1 to mean "there was an error". But this could be confusing if the hash worked correctly, and the actual hash of an object was -1. So the convention is: if hashing worked, and you got a -1, return -2.

There's special code in the hash function for ints ("long objects") in CPython that does exactly that:

https://github.com/python/cpython/blob/main/Objects/longobject.c#L2967

And the mentioned CPython code snippet is:

static Py_hash_t
long_hash(PyObject *obj)
{
    Py_uhash_t x;
    // ...
    if (x == (Py_uhash_t)-1)
        x = (Py_uhash_t)-2;
    return (Py_hash_t)x;
}

Checklist before calling for maintainers

  • Have you checked to ensure there aren't other open Issues for the same update/change?
  • Have you checked that this snippet is not similar to any of the existing snippets?
  • Have you added an Explanation section? It shall include the reasons for changes and why you'd like us to include them

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions