Storing 'unhashable' types in dictionaries by address
Tim Peters
tim_one at email.msn.com
Sun May 25 12:52:02 EDT 2003
[Ed Avis]
> A dictionary requires that its key type be hashable. This means you
> cannot use lists as keys of a dictionary. Is there any way round
> this?
Several, all requiring that you not use lists as keys <wink>.
> I would like to store some 'extra' information associated with some
> lists, but do so outside the lists themselves. For example this is
> what I would like to write:
>
> l0 = ['strawberry']
> l1 = ['mint', 'choc']
> l2 = ['vanilla', 'liver']
>
> # This dictionary stores some extra comments on each flavour.
> d = {}
> d[l0] = 'yum'
> d[l1] = 'so-so'
> d[l2] = 'ugh'
>
> print d[l0] # prints 'yum'
> l0.append(55)
> print d[l0] # still prints 'yum', since it's the same list
>
> # Now I construct a new list which, although it contains the same
> # strings as l1, is a different object. This is just to demonstrate
> # that d indexes by 'is' rather than by ==.
> #
> new_list = ['mint', 'choc']
> print new_list in d.keys() # prints 0, or false
>
>
> I hope the intent is clear - I want to look up by object identity and
> not by the contents of the list.
>
> Something which would be almost as good is to take the address of a
> list or other object, then I could use that as the key of a
> dictionary.
The builtin function id(x) returns the "object identity" of x, which you can
think of as being its address. The Python expression
x is y
is equivalent to
id(x) == id(y)
barring pathologies involving overly clever expansions for "x" and "y".
> Is there any library which can do what I want, either by providing its
> own dictionaries which don't require objects to be hashable,
I'm sure someone must have written one, but I don't know where offhand and
wouldn't bother if I did.
> or by letting the programmer get the address of an object?
id() does that.
Another possibility is to create a subclass of list (Python 2.2 or later),
overriding list's __hash__ and __eq__ methods. For example, this program
prints what the comments say it prints; it should look familiar <wink>:
"""
class idlist(list):
def __hash__(self):
return hash(id(self))
def __eq__(self, other):
return id(self) == id(other)
l0 = idlist(['strawberry'])
l1 = idlist(['mint', 'choc'])
l2 = idlist(['vanilla', 'liver'])
d = {}
d[l0] = 'yum'
d[l1] = 'so-so'
d[l2] = 'ugh'
print d[l0] # prints 'yum'
l0.append(55)
print d[l0] # still prints 'yum', since it's the same list
new_list = idlist(['mint', 'choc'])
print new_list in d.keys() # prints 0 (2.2.2) or False (2.3)
print new_list in d # the same, but much more efficient
print d.has_key(new_list) # also much more efficient
"""
Do note the last two lines, which didn't appear in your original.
More information about the Python-list
mailing list