tags:

views:

79

answers:

3

I'm trying to eliminate duplicates of an array containing a few thousands of custom objects. For this I'm implementing the __hash__ and __cmp__ functions for these objects.

Is it safe to delegate these functions to one of the objects' fields (a guaranteed unique string) ?

I.e.

class A:

     def __init__(self, key, etc...):
         self.key = key
         ...

     def __hash__(self):
         return self.key.__hash__()

     def __cmp__(self, other):
         return cmp(self.key, other.key)

# then somewhere in code with arr being array of A

unique = sorted(set(arr))

Any hint greatly appreciated!

+2  A: 

Yes. The only requirement of __hash__ is that it be unique. In fact, this is quite an elegant and Pythonic way of solving the problem!

EDIT: It has been pointed out to me that __hash__ need not even be unique! Instead, one simply requires equal objects to have the same hash. Unequal ones may also have the same hash; in fact, everything could hash to 0 and this would be (technically) fine.

katrielalex
No, two objects may have the same hash values, so that hash(x) == hash(y) and x != y.That would be perfectly ok.
pillmuncher
It does look pretty, problem is something's not working at the moment :) Sorting this way (seemingly same) two arrays of ~2500 objects yielded two sets of different sizes.
Sergey
+1  A: 

Eschew __cmp__. Python3 no longer supports this special method, and recommends using __lt__ instead.

def __lt__(self,other):
    return self.key < self.other
unutbu
Thanks, I'll keep that in mind!
Sergey
+1  A: 

Two unequal objects may have the same hash value, but two equal objects may not have different hash values. The law:

a == b --> hash(a) == hash(b) 

describes this. Otherwise you couldn't use them as dict keys or put them is sets. Well, maybe you could add them, but you couldn't retrieve them later.

So, when delegating __hash__(), I always define __eq__() as well, just to be on the safe side:

def __hash__(self):
    return hash(self.key)

def __eq__(self, other):
    return self.key == other.key

Since you want to sort your objects, you must also add unutbus __lt__().

pillmuncher
Thanks, that's the law I wasn't sure of.
Sergey