-1

Reading How to implement a good __hash__ function in python - can I not write eq as

def __eq__(self, other):
    return isinstance(other, self.__class__) and hash(other) == hash(self)

def __ne__(self, other):
    return not self.__eq__(other)

def __hash__(self):
    return hash((self.firstfield, self.secondfield, totuple(self.thirdfield)))

? Of course I am going to implement __hash__(self) as well. I have rather clearly defined class members. I am going to turn them all into tuples and make a total tuple out of those and hash that.

Community
  • 1
  • 1
Make42
  • 12,236
  • 24
  • 79
  • 155

2 Answers2

4

Generally speaking, a hash function will have collisions. If you define equality in terms of a hash, you're running the risk of entirely dissimilar items comparing as equal, simply because they ended up with the same hash code. The only way to avoid this would be if your class only had a small, fixed number of possible instances, and you somehow ensured that each one of those had a distinct hash. If your class is simple enough for that to be practical, then it is almost certainly simple enough for you to just compare instance variables to determine equality directly. Your __hash__() implementation would have to examine all the instance variables anyway, in order to calculate a meaningful hash.

jasonharper
  • 9,450
  • 2
  • 18
  • 42
  • That is kind of my point: My `__hash(self)__` needs to consider all the relevant fields of my class. Why should I reimplement that for equality again? – Make42 Nov 01 '16 at 15:58
  • 1
    Because it is unlikely that your ``__hash__`` is capable of considering all of the relevant fields in such a way that it guarantees unequal values for unequal objects. Does your object contain more than one int field? It's impossible to combine two arbitrary ints into a single hash code without collision. Does it contain even a single string field? A str has vastly more possible values than an int can distinguish. – jasonharper Nov 01 '16 at 16:06
  • Well I know, that I would not be able to just add the integers or something like that. I added to the question what I was planning to do. – Make42 Nov 01 '16 at 16:18
  • @Make42: `tuple.__hash__` isn't collision-free either, so that's not going to work. – user2357112 Nov 01 '16 at 16:22
  • @user2357112: So what is `__hash__` good for - just for hashtables, hash-based collection (like dictionary) and a "likelihood to be the same"? – Make42 Nov 02 '16 at 14:03
  • @Make42: It's basically just for dicts and sets. – user2357112 Nov 02 '16 at 16:24
1

Of course you can define __eq__ and __ne__ the way you have in your example, but unless you also explicitly define __hash__, you will get a TypeError: unhashable type exception any time you try to compare equality between two objects of that type.

Since you're defining some semblance of value to your object by defining an __eq__ method, a more important question is what do you consider the value of your object to be? By looking at your code, your answer to that is, "the value of this object is it's hash". Without knowing the contents of your __hash__ method, it's impossible to evaluate the quality or validity of your __eq__ method.

Billy
  • 5,179
  • 2
  • 27
  • 53