How does a Python set([]) check if two objects are equal? What methods does an object need to define to customise this?

Ada picture Ada · Oct 15, 2010 · Viewed 45.1k times · Source

I need to create a 'container' object or class in Python, which keeps a record of other objects which I also define. One requirement of this container is that if two objects are deemed to be identical, one (either one) is removed. My first thought was to use a set([]) as the containing object, to complete this requirement.

However, the set does not remove one of the two identical object instances. What must I define to create one?

Here is the Python code.

class Item(object):
  def __init__(self, foo, bar):
    self.foo = foo
    self.bar = bar
  def __repr__(self):
    return "Item(%s, %s)" % (self.foo, self.bar)
  def __eq__(self, other):
    if isinstance(other, Item):
      return ((self.foo == other.foo) and (self.bar == other.bar))
    else:
      return False
  def __ne__(self, other):
    return (not self.__eq__(other))

Interpreter

>>> set([Item(1,2), Item(1,2)])
set([Item(1, 2), Item(1, 2)])

It is clear that __eq__(), which is called by x == y, is not the method called by the set. What is called? What other method must I define?

Note: The Items must remain mutable, and can change, so I cannot provide a __hash__() method. If this is the only way of doing it, then I will rewrite for use of immutable Items.

Answer

ruena picture ruena · Jun 25, 2013

Yes, you need a __hash__()-method AND the comparing-operator which you already provided.

class Item(object):
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar
    def __repr__(self):
        return "Item(%s, %s)" % (self.foo, self.bar)
    def __eq__(self, other):
        if isinstance(other, Item):
            return ((self.foo == other.foo) and (self.bar == other.bar))
        else:
            return False
    def __ne__(self, other):
        return (not self.__eq__(other))
    def __hash__(self):
        return hash(self.__repr__())