Storing 'unhashable' types in dictionaries by address

Tim Peters tim_one at email.msn.com
Sun May 25 18:36:30 EDT 2003


[Ed Avis]
> ...
> Clearly, though, you can't then call keys() on the dictionary and get
> back an original object, only its address.

You can if you use the list subclass at the end of my msg.

> However you can imagine a special dictionary-like class that
> automatically calls id on keys that need it,

I doubt it could distinguish keys "that need it" from keys that don't
without making up arbitrary rules, or growing a pile of confusing options.
For example, sometimes it's useful to have dicts keyed by object id even
when the keys are of hashable types.

> internally keeps track of the object corresponding to each address, and
> then returns keys that are live objects.  In other words
> it would present an interface that lets you shove objects into and out
> of dictionaries - as keys or as values - with impunity.
>
> I didn't see such a class in the Python standard library but does one
> exist somewhere?  (You said you did not know of any but maybe others
> will.)

It's so easy that I doubt you're going to find anyone bothering to maintain
such a module for public use.  A more interesting twist requires a more
recent version of Python:

> ...
> I'm still using Python 1.5.2 (at least on the box I post to newsgroups
> with) ...

More modern Pythons have grown weak references, so that in the kind of dict
you imagine, under the covers an id-to-object WeakValueDictionary can be
used to maintain the id->object inverse mapping without keeping the objects
artificially alive ... in fact, that's an example in current docs:

    http://www.python.org/doc/current/lib/weakref-example.html

Another possibility is to use a wrapper class with a regular dict, like
(untested):

class Wrapper:
    def __init__(self, obj):
        self.obj = obj
    def __hash__(self):
        return hash(self.obj)
    def __eq__(self, other):
        return id(self.obj) == id(other.obj)

So instead of using a list directly as a key, use Wrapper(list) as a key in
a regular dict.  Extracting the original object from a Wrapper object later
is trivial (after w = Wrapper(x), x is w.obj).






More information about the Python-list mailing list