tags:

views:

331

answers:

2

I have a list of objects which I want to turn into a set. My objects contain a few fields that some of which are o.id and o.area. I want two objects to be equal if these two fields are the same. ie: o1==o2 if and only if o1.area==o2.area and o1.id==o2.id.

I tried over-writing __eq__ and __cmp__ but I get the error: TypeError: unhashable instance.

What should I over-write?

+11  A: 

Define the __hash__ method to return a meaningful hash based on the id and area fields. E.g.:

def __hash__(self):
    return hash(self.id) ^ hash(self.area)
Marcelo Cantos
I'm a little leery of bitwise math on something like that. I'd use something like =return hash((self.id, self.area))=.
Just Some Guy
This is likely to be a problem when hashing two similar components. For instance hash(x) ^ hash(y) will misbehave if coordinates pair with swapped axes are common. In this case, it is extremely unlikely to cause problems since it is impossible to generate ints and strings with correlated hashes. Having said that, your suggestion is still a good one, which I wish I'd thought of :-).
Marcelo Cantos
+2  A: 

"TypeError: unhashable instance." error is probably due to old-style class definition i.e.:

class A:
  pass

Use new style instead:

class A(object):
  pass

If you override __cmp__ function you should override __hash__ for using your object in sets. In the other case hash considers all object instances as unequal and __cmp__ function will never be called.

Yaroslav