Home » Python » Compare object instances for equality by their attributes in Python

Compare object instances for equality by their attributes in Python

Posted by: admin November 1, 2017 Leave a comment

Questions:

What is the best way to compare two instances of some object for equality in Python? I’d like to be able to do something like

Example:

doc1 = ErrorDocument(path='/folder',title='Page')
doc2 = ErrorDocument(path='/folder',title='Page')

if doc1 == doc2: # this should be True
    #do something

EDIT:

To further clarify the question. I’d like to compare by attribute values, and to make a more generic solution than

def __eq__(self, other):
    return self.path == other.path and self.title == other.title

Should the __eq__() method look something like this?

def __eq__(self, other):
    # Is the other instance of the same object
    # Loop through __dict__ and compare values to attributes of other
Answers:

As usual with Python, it’s KISS:

class Test(object):

    def __init__(self, attr1, attr2):
        self.attr1 = attr1
        self.attr2 = attr2

    def __str__(self):
        return str(self.__dict__)

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

t1 = Test("foo", 42)
t2 = Test("foo", 42)
t3 = Test("bar", 42)

print t1, t2, t3
print t1 == t2
print t2 == t3

It outputs:

{'attr2': 42, 'attr1': 'foo'} {'attr2': 42, 'attr1': 'foo'} {'attr2': 42, 'attr1': 'bar'}
True
False

N.B.: be aware that before Python 3.0, you are more likely to use __cmp__ instead of __eq__, working the same way.

Questions:
Answers:

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

Questions:
Answers:

Implement the __eq__ method in your class; something like this:

def __eq__(self, other):
    return self.path == other.path and self.title == other.title

Edit: if you want your objects to compare equal if and only if they have equal instance dictionaries:

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

Questions:
Answers:

As a summary :

  1. It’s advised to implement __eq__ rather than __cmp__, except if you run python <= 2.0 (__eq__ has been added in 2.1)
  2. Don’t forget to also implement __ne__ (should be something like return not self.__eq__(other) or return not self == other except very special case)
  3. Don`t forget that the operator must be implemented in each custom class you want to compare (see example below).
  4. If you want to compare with object that can be None, you must implement it. The interpreter cannot guess it … (see example below)

    class B(object):
      def __init__(self):
        self.name = "toto"
      def __eq__(self, other):
        if other is None:
          return False
        return self.name == other.name
    
    class A(object):
      def __init__(self):
        self.toto = "titi"
        self.b_inst = B()
      def __eq__(self, other):
        if other is None:
          return False
        return (self.toto, self.b_inst) == (other.toto, other.b_inst)
    
Questions:
Answers:

When comparing instances of objects, the __cmp__ function is called.

If the == operator is not working for you by default, you can always redefine the __cmp__ function for the object.

Edit:

As has been pointed out, the __cmp__ function is deprecated since 3.0.
Instead you should use the “rich comparison” methods.

Questions:
Answers:

If you want to get an attribute-by-attribute comparison, and see if and where it fails, you can use the following list comprehension:

[i for i,j in 
 zip([getattr(committed_vans_events[0][0].request, attr) 
      for attr in dir(committed_vans_events[0][0].request)],
     [getattr(self.vans_states[0].onboard_passengers[0], attr) 
      for attr in dir(self.vans_states[0].onboard_passengers[0])]) 
 if not i==j]

The extra advantage here is that you can squeeze it one line and enter in the “Evaluate Expression” window when debugging in PyCharm.

Questions:
Answers:

I tried the initial example (see 7 above) and it did not work in ipython. Note that cmp(obj1,obj2) returns a “1” when implemented using two identical object instances. Oddly enough when I modify one of the attribute values and recompare, using cmp(obj1,obj2) the object continues to return a “1”. (sigh…)

Ok, so what you need to do is iterate two objects and compare each attribute using the == sign.

Questions:
Answers:

Instance of a class when compared with == comes to non-equal. The best way is to ass the cmp function to your class which will do the stuff.

If you want to do comparison by the content you can simply use cmp(obj1,obj2)

In your case cmp(doc1,doc2) It will return -1 if the content wise they are same.