3

I'm using Python 3.6. Suppose that I'm trying to keep a unique set of tuples. I know I can use tuple in set and get back the correct result (the set contains the tuple or not).

s = set()
t1 = (1, 2)
t2 = (1, 2)
s.add(t1)
print(t2 in s) # True -- Great!

Now, suppose I have a custom class that contains a tuple. I would like to define uniqueness for the custom class objects as uniqueness for the tuple. I did the following:

class TupleWrapper(object):

    def __init__(self, t):
        self.t = t # tuple

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


s = set()
t1 = TupleWrapper((1, 2))
s.add(t1)
t2 = TupleWrapper((1, 2))
print(t2 in s) # False -- WHY?

I wrote my own __hash__() method that hashes the tuple. So why are the two TupleWrapper objects with the same tuple not found to be the same in the set? Do I need to override another method?

stackoverflowuser2010
  • 38,621
  • 48
  • 169
  • 217

1 Answers1

7

you need to implement __eq__ on TupleWrapper as well.

def __eq__(self, other):
    if isinstance(other, TupleWrapper):
        return self.t == other.t
    return NotImplemented

otherwise, when checking to see if the object is already in the set, it will default to identity comparison, which is just is (i.e., t1 is t2 or id(t1) == id(t2)).

more detail: loosely speaking, on insertion, set (and dict) first use the hash value to figure out which bucket things are in. then, in that bucket, it uses == to check, in the case of a hash collision, if that object is already there.

hash documentation here

acushner
  • 9,595
  • 1
  • 34
  • 34
  • 2
    Thank you. How would I know that `thing in set` would call `thing.__eq__(other)`? Is it documented clearly somewhere? – stackoverflowuser2010 Jan 21 '21 at 03:04
  • 3
    @stackoverflowuser2010: `__eq__` is the overload hook for `==` equality comparisons. – user2357112 Jan 21 '21 at 03:05
  • 4
    @stackoverflowuser2010 for starters, https://docs.python.org/3/reference/datamodel.html#object.__hash__ – juanpa.arrivillaga Jan 21 '21 at 03:05
  • 1
    @stackoverflowuser2010 Also, the [definition of hashable in Python](https://docs.python.org/3/glossary.html#term-hashable) which is linked to from the [documentation for sets](https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset) – juanpa.arrivillaga Jan 21 '21 at 03:12