3

I was learning about python hash function and came across the following behavior.

>>> hash(-1)
-2
>>> hash(-2)
-2

SO already has a great post which answers why: Why do -1 and -2 both hash to -2 in CPython?

Since python dictionary uses hash of the key to store the value, the following output is expected because both True and 1 has same hash:

>>> my_dict = { True: "true", 1: "one"}
>>> my_dict
{True: 'one'}
>>> hash(True)
1
>>> hash(1)
1

But if I try with the following, I expect the output as { -1: "Minus Two"}, since -1 and -2 has same hash. But that was not the case.

>>> my_dict = { -1: "Minus One", -2: "Minus Two"}
>>> my_dict
{-1: 'Minus One', -2: 'Minus Two'}
>>> hash(-1)
-2
>>> hash(-2)
-2

What is the reason for this behavior?. Don't dictionaries use the hash of the key to store it's value?

NOTE: I know it's CPython specific, but I'm curious to know the reason for this behavior.

Seth
  • 2,214
  • 1
  • 7
  • 21
Abdul Niyas P M
  • 18,035
  • 2
  • 25
  • 46
  • If it only uses hash value, then it is totally useless, right? You cannot confidently store anything in it, as you cannot ensure they have different hash values. Yes, it uses hash value, but will also check the equality if hash values are the same. – Sraw Dec 16 '20 at 05:16
  • Btw, it is not CPython specific, all hash dictionaries have a similar implementation. The only reason you see this behavior is just because `1 == True` at least in CPython. – Sraw Dec 16 '20 at 05:18
  • 1
    "Since python dictionary uses hash of the key to store the value, the following output is expected because both True and 1 has same hash." NO. That fact by itself *does not imply that*. Both the *hash* and *equality* have to be consistent. – juanpa.arrivillaga Dec 16 '20 at 05:24

1 Answers1

3

Not only does it check the hash value of an object, it also checks the equality of it. You can see this in effect with this example:

>>> class Samesies:
...     def __hash__(self):
...             return 1
...     def __eq__(self, other):
...             return True
...
>>> {Samesies(): 1, Samesies(): 2}
{<__main__.Samesies object at 0x0000023997ACEFA0>: 2}

EDIT: The reason that 1 == True and hash(1) == hash(True) is due to the fact that bool actually subclasses int.

Seth
  • 2,214
  • 1
  • 7
  • 21