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