Alex Rivera | Logout

objects as keys in python dictionaries

Asked 2011-02-09T20:34:40.707
35

I'm trying to use an object as a key in a python dictionary, but it's behaving in a way that I can't quite understand.

First I create a dictionary with my object as the key:

package_disseminators = {
  ContentType("application", "zip", "http://other/property") : "one",
  ContentType("application", "zip") : "two"
}

Now create another object that is "the same" as one which is a key.

content_type = ContentType("application", "zip", "http://other/property")

I have given the ContentType object custom __eq__ and custom __str__ methods, such that the __eq__ method compares the __str__ values.

Now, some interactive python:

>>> for key in package_disseminators:
...     if key == content_type:
...             print "match"
...     else:
...             print "no match"
... 
no match
match

>>> content_type in package_disseminators.keys()
True

Ok, so it looks like my object is definitely being identified properly as a key, so:

>>> package_disseminators[content_type]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: (& (type="application/zip") (packaging="http://other/property") )

Er ... ok? So content_type is in the package_disseminators.keys() list, but isn't a key?

>>> package_disseminators.has_key(content_type)
False

Apparently not.

I presume that the comparison process that Python uses to determin equality differs between a straight "in" statement on a list and actually looking up a key in a dict, but I don't know how. Any tips or insights?

Edit
Report

1 Answer

38

Since dicts are hash tables under the hood, you need to define both __eq__ and __hash__ for that to work.

The basic rule of thumb is:

  • For objects that __eq__ compares equal, __hash__ must return the same hash.

From your description, something like

def __hash__(self):
    return hash(str(self))

should work.

answered 2011-02-09T20:42:39.487

Your Answer