2

When reading about how to implement __eq__ in python, such as in this SO question, you get recommendations like

class A(object):
    def __init__(self, a, b):
        self._a = a
        self._b = b

    def __eq__(self, other):
        return (self._a, self._b) == (other._a, other._b)

Now, I'm having problems when combining this with inheritance. Specifically, if I define a new class

class B(A):
    def new_method(self):
        return self._a + self._b

Then I get this issue

>>> a = A(1, 2)
>>> b = B(1, 2)
>>> a == b
True

But clearly, a and b are not the (exact) same!

What is the correct way to implement __eq__ with inheritance?

Jonas Adler
  • 10,365
  • 5
  • 46
  • 73
  • 1
    How are you defining equality? Is `type` an important part of your equality test, e.g. `1 == True` is `True` but obviously they are not the same type. From an `a` perspective isn't `b` equal to the `a`. You may implement equality differently for `b`, `a == b` but that doesn't mean `b == a`. – AChampion Jul 20 '17 at 13:35

2 Answers2

6

If you mean that instances of different (sub)classes should not be equal, consider comparing their types as well:

def __eq__(self, other):
    return (self._a, self._b, type(self)) == (other._a, other._b, type(other))

In this way A(1, 2) == B(1,2) returns False.

Błotosmętek
  • 12,717
  • 19
  • 29
3

When performing a comparison between objects of two types where one type is derived from the other, Python ensures that the operator method is called on the derived class (in this case, B).

So to ensure that B objects compare dissimilarly to A objects, you can define __eq__ in B:

class B(A):
    def __eq__(self, other):
        return isinstance(other, B) and super(B, self).__eq__(other)
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • @AChampion `B.__eq__` overrides `A.__eq__`, so `a == b` calls `B.__eq__(b, a)`. [Example](https://ideone.com/x0LQAo). – ecatmur Jul 20 '17 at 13:49
  • Bad assumption on my part, thanks. Is there rational for this given `a` is of type `A` not `B`. – AChampion Jul 20 '17 at 13:52