I'm wondering what is the general way to define __hash__. I could add
up all the members. But I am wondering if this would cause a
performance issue for certain classes.
def __init__(self, a, b) :
self._a = a
self._b = b
return 'A(%s, %s)' %(self._a, self._b)
__repr__ = __str__
def __cmp__(self, other):
if self._a < other._a:
elif self._a > other._a:
elif self._b < other._b:
elif self._b > other._b:
return self._a + self._b
if __name__ == '__main__':
x = A(1, 1)
aset = set()
What if A has a third member, which is a string? Is there a function
to convert an arbitrary string to an int?
Unless if you are very familiar with the math of hash functions, I don't
recommend that you try to implement one directly. Instead, make a tuple of the
hashable content of your class and return the result of calling hash() on that
tuple. Be sure to make your equality comparison do the right thing.
def __init__(self, a, b):
self.a = a
self.b = b
# I include the name of the class so as to differentiate between other
# classes that might also have a _key() method. If you have several classes
# or subclasses that are allowed to compare equal to each other, use some
# other common string here.
return (type(self).__name__, a, b)
# Coincidentally, the _key() method can usually be reused for comparisons.
# I recommend doing this for the equality comparisons, at least, when you can
# because of the requirement that two items that compare equal must have the
# same hash value.
def __eq__(self, other):
return self._key() == other._key()
def __ne__(self, other):
return not (self == other)
"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
> def __hash__(self):
> return self._a + self._b
The hash of a tuple is based on the hash of its values. A common way to
define a hash method is:
return hash((self._a, self._b))
Do I need to define other 4 comparison operators besides __eq__ and __ne__?
No; dictionaries are unordered and thus don't utilize the non-equality
Yes. There are recipes to fill in the rest if you just provide __eq__ and __lt__:
Or you could continue to use the __cmp__ method, but it will be going away in
> def __cmp__(self, other):
> if self._a < other._a:
> return -1
> elif self._a > other._a:
> return 1
> elif self._b < other._b:
> return -1
> elif self._b > other._b:
> return 1
> return 0
This can be simplified to:
return cmp((self._a, self._b), (other._a, other._b))
Assuming you're not using Python 3.x that is.
If you're using Python 3, you won't be writing a __cmp__
method in the first place.