Compare object instances for equality by their attributes in Python


Question

I have a class MyClass, which contains two member variables foo and bar:

class MyClass:
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar

I have two instances of this class, each of which has identical values for foo and bar:

x = MyClass('foo', 'bar')
y = MyClass('foo', 'bar')

However, when I compare them for equality, Python returns False:

>>> x == y
False

How can I make python consider these two objects equal?

1
211
3/22/2019 10:47:08 PM

Accepted Answer

You should implement the method __eq__:

class MyClass:
    def __init__(self, foo, bar):
        self.foo = foo
        self.bar = bar

    def __eq__(self, other): 
        if not isinstance(other, MyClass):
            # don't attempt to compare against unrelated types
            return NotImplemented

        return self.foo == other.foo and self.bar == other.bar

Now it outputs:

>>> x == y
True

Note that implementing __eq__ will automatically make instances of your class unhashable, which means they can't be stored in sets and dicts. If you're not modelling an immutable type (i.e. if the attributes foo and bar may change value within the lifetime of your object), then it's recommend to just leave your instances as unhashable.

If you are modelling an immutable type, you should also implement the datamodel hook __hash__:

class MyClass:
    ...

    def __hash__(self):
        # necessary for instances to behave sanely in dicts and sets.
        return hash((self.foo, self.bar))

A general solution, like the idea of looping through __dict__ and comparing values, is not advisable - it can never be truly general because the __dict__ may have uncomparable or unhashable types contained within.

N.B.: be aware that before Python 3, you may need to use __cmp__ instead of __eq__. Python 2 users may also want to implement __ne__, since a sensible default behaviour for inequality (i.e. inverting the equality result) will not be automatically created in Python 2.

303
3/22/2019 11:27:47 PM

You override the rich comparison operators in your object.

class MyClass:
 def __lt__(self, other):
      # return comparison
 def __le__(self, other):
      # return comparison
 def __eq__(self, other):
      # return comparison
 def __ne__(self, other):
      # return comparison
 def __gt__(self, other):
      # return comparison
 def __ge__(self, other):
      # return comparison

Like this:

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

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon