Python: Accessing dict with hashable object fails

I am using a hashable object as a key to a dictionary. The objects are hashable and I can store key-value-pairs in the dict, but when I create a copy of the same object (that gives me the same hash), I get a KeyError.

Here is some small example code:

class Object:
    def __init__(self, x): self.x = x
    def __hash__(self): return hash(self.x)

o1 = Object(1.)
o2 = Object(1.)
hash(o1) == hash(o2) # This is True
data = {}
data[o1] = 2.
data[o2] # Desired: This should output 2.

In my scenario above, how can I achieve that data[o2] also returns 2.?

3 answers

  • answered 2022-01-25 13:37 Allan Chua

    You can use the __eq__ magic method to implement a equality check on your object.

        def __eq__(self, other):
            if (isinstance(other, C)):
                return self.x == self.x

    You can learn more about magic methods from this link.

  • answered 2022-01-25 13:38 Bharel

    You need to implement both __hash__ and __eq__:

    class Object:
        def __init__(self, x): self.x = x
        def __hash__(self): return hash(self.x)
        def __eq__(self, other): return self.x == other.x if isinstance(other, self.__class__) else NotImplemented

    Per Python documentation:

    if a class does not define an __eq__() method it should not define a __hash__() operation either

    After finding the hash, Python's dictionary compares the keys using __eq__ and realize they're different, that's why you're not getting the correct output.

  • answered 2022-01-25 13:44 RomainL.

    So as stated before your object need to implement __ eq__ trait (equality ==), If you want to understand why:

    Sometimes hash of different object are the same, this is called collision. Dictionary manages that by testing if the objects are equals. If they are not dictionary has to manage the collision. How they do that Is implementation details and can vary a lot. A dummy implementation would be list of tuple key value.

    Under the hood, a dummy implementation may look like that :

    dico[key] = [(object1, value), (object2, value)]

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum