1

Take this super simple class:

class Foo():
    def __init__(self, iden):
        self.iden = iden
    def __hash__(self):
        return hash(self.iden)
    def __repr__(self):
        return str(self.iden)

The goal is to create instances of the class to use as dict keys. If __repr__ is omitted, the keys are the standard object address. With __repr__ a printable representation might be:

f = Foo(1)
g = Foo(2)
d = {f:'a', g:'b'}
print(d)
>>> {1:'a', 2:'b'}

When attempting to access the dict by key though, it does not appear to be immediately obvious how to utilize the __repr__ (or __str__ for that matter) representation as the key.

print(d[1]) 
>>> KeyError
Jzl5325
  • 3,898
  • 8
  • 42
  • 62
  • 4
    How to utilize `__str__`/`__repr__` to do *what*, exactly? An object's place in a `dict` (or `set`) is based only on its hash. `__repr__` only affects how an object _appears_, not how you can reference it. – glibdud Nov 22 '17 at 16:11
  • The answer is no. As I said, the repr is only relevant to how the object is _displayed_, not how you can reference it. – glibdud Nov 22 '17 at 16:27
  • @glibdud The above fails using `__hash__` as well. `hash(1) == 1`, but `d[1]` fails with a key error. – Jzl5325 Nov 22 '17 at 16:28
  • Good point. It appears that something else (possibly type?) is taken into account in addition to hash. I'll see if I can find a reference. – glibdud Nov 22 '17 at 16:31

1 Answers1

4

First thing's first: __repr__() is a red herring. It only affects how the object is displayed. It has nothing to do with what you're trying to do.

If you want to have two separate objects refer to the same slot in a dict, you need two things (reference):

  • The objects must have the same hash (hash(obj1) == hash(obj2)).
  • The objects must compare equal (obj1 == obj2).

Your above implementation does the former, but not the latter. You need to add an __eq__() method (which is actually required by the documentation when you define __hash__(), anyway).

class Foo():
    def __init__(self, iden):
        self.iden = iden
    def __hash__(self):
        return hash(self.iden)
    def __eq__(self, other):
        return self.iden == other

 

>>> d = {Foo(1) : 'a'}
>>> d[1]
'a'
glibdud
  • 7,550
  • 4
  • 27
  • 37