Unexpected behavior with dictionary keys containment and a user-defined class

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Tue Jan 13 05:05:57 CET 2009

On Mon, 12 Jan 2009 22:41:00 -0500, Rob Clewley wrote:

> Hi, the short version of my question is: when is a dictionary's
> __contains__ method behavior different to using the 'in' idiom? (because
> I have an example of a difference in my code).


> i in d.keys()  and  d.keys()[10] == i
> both return True. But
> d.__contains__(i)
> d.has_key(i)
> d.keys()[10] is i

The instance you are testing for isn't the same instance as the one in 
the dictionary. It might be *equal*, but it isn't identical, and by 
default, hashing of classes goes by identity. You need to give your class 
a hash function so that whenever x==y hash(x)==hash(y) as well.

That means you need to over-ride __hash__(self) in the class.

> return False. I put a print statement in my class's __eq__ method and it
> is being called. It tests equality of some of my class instance's
> attributes. I didn't realize there was any situation where you could
> expect different results from   i in d   versus   i in d.keys()   -- am
> I misunderstanding something?

i in d.keys() does an item-by-item equality test, returning the first 
time i is equal to an item.

i in d hashes i, then looks up a table to see whether there is an item in 
that spot. If there is, it compares that item to i for equality.


More information about the Python-list mailing list