One of the most common questions I get asked by python beginners, is “how do you compare between objects of a class?”

To answer this question, let’s have a look on the following class:

A basic class which represents a Ball. The ball has size and color which are the attributes. Two balls are equal if they match in size and color. So red small ball would only match another red small ball.

Now, some python beginners expect the following code, to output True:

But it doesn’t compare the balls as we might think it does. What Python is doing is to compare the id of ball1 and ball2, but their ids are actually different

So what would be the right way to compare? Fortunately, Python has several comparison methods just for that.

Comparison methods

The comparison methods were first introduced in Python 2.1 and they are also called ‘rich comparison methods’ or ‘comparison magic methods’

A few important notes on using these methods:

  • The most common usage is to return False or True when using one of the rich comparison methods, but you can actually return any value you want, it really depends on the context of how you use them.
  • If x == y it doesn’t mean that x != y. The best practice is always to define __ne__() if __eq__() was defined.
  • A rich comparison method may return “NotImplemented” if the operation is not implemented for a given pair of arguments

Let’s  add __eq__ and __ne__ to our ‘Ball’ class:

That’s better, but still not exactly what we wanted. We added two methods. One for comparing the equality of two  Ball objects and the __ne__  method for inequality.

We said that two balls are equal if they have the  same size and color (and indeed the program output was true when comparing ball1 to ball2) and they are unequal if one of the properties is different (size or color) and in this case also the output was correct (False) for ball1 compared to ball3.

So what  is the problem you ask?

A ball is not a box

Let’s say we have this additional class to represent a Box:

Identical to Ball, except this is a Box 🙂 What will the last line print?

If you guessed ‘False’ then you are wrong. It will print True. Now you might be sitting your chair screaming “but a box is not a ball!” and the good news are that you absolutely right 🙂

To fix that we need to change our __eq__ and __ne__ methods:

We added one simple check to fix the issue: “if isinstance(object, classinfo)” which returns True in case the object is an instance of the classinfo argument. In our case. it will check if a Ball is an instance of a Box or a Ball (depends what we compare against).

Now you may ask yourself “both Box class and Ball class has __eq__ method. Which one is used when comparing?”

The answer is simple – it depends on which one is the first in the comparison. The __eq__ method of the left side operand would be used. Take this lone for example:

It would run Box class __eq__ method. If it was the ball on the left side (as for ball1 == box1) then it would use the __eq__ method of the Ball class.