简体   繁体   中英

Most efficient way of comparing the contents of two class instances in python

I'm looking for the most efficient way of comparing the contents of two class instances. I have a list containing these class instances, and before appending to the list I want to determine if their property values are the same. This may seem trivial to most, but after perusing these forums I wasn't able specific to what I'm trying to do. Also note that I don't have an programming background.

This is what I have so far:

class BaseObject(object):
    def __init__(self, name=''):
        self._name = name


    def __repr__(self):
        return '<{0}: \'{1}\'>'.format(self.__class__.__name__, self.name)

    def _compare(self, other, *attributes):
        count = 0
        if isinstance(other, self.__class__):
            if len(attributes):
                for attrib in attributes:
                    if (attrib in self.__dict__.keys()) and (attrib in other.__dict__.keys()):
                        if self.__dict__[attrib] == other.__dict__[attrib]:
                            count += 1
                return (count == len(attributes))
            else:
                for attrib in self.__dict__.keys():
                    if (attrib in self.__dict__.keys()) and (attrib in other.__dict__.keys()):
                        if self.__dict__[attrib] == other.__dict__[attrib]:
                            count += 1
                return (count == len(self.__dict__.keys()))
    def _copy(self):
        return (copy.deepcopy(self))

Before adding to my list, I'd do something like:

found = False
for instance in myList:
    if instance._compare(newInstance): 
        found = True
        Break

if not found: myList.append(newInstance)

However I'm unclear whether this is the most efficient or python-ic way of comparing the contents of instances of the same class.

Implement a __eq__ special method instead:

def __eq__(self, other, *attributes):
    if not isinstance(other, type(self)):
        return NotImplemented

    if attributes:
        d = float('NaN')  # default that won't compare equal, even with itself
        return all(self.__dict__.get(a, d) == other.__dict__.get(a, d) for a in attributes)

    return self.__dict__ == other.__dict__

Now you can just use:

if newInstance in myList:

and Python will automatically use the __eq__ special method to test for equality.

In my version I retained the ability to pass in a limited set of attributes:

instance1.__eq__(instance2, 'attribute1', 'attribute2')

but using all() to make sure we only test as much as is needed.

Note that we return NotImplemented , a special singleton object to signal that the comparison is not supported; Python will ask the other object if it perhaps supports equality testing instead for that case.

You can implement the comparison magic method __eq__(self, other) for your class, then simply do

if instance == newInstance:

As you apparently don't know what attributes your instance will have, you could do:

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

Your method has one major flaw: if you have reference cycles with classes that both derive from BaseObject , your comparison will never finish and die with a stack overflow.

In addition, two objects of different classes but with the same attribute values compare as equal. Trivial example: any instance of BaseObject with no attributes will compare as equal to any instance of a BaseObject subclass with no attributes (because if issubclass(C, B) and a is an instance of C , then isinstance(a, B) returns True ).

Finally, rather than writing a custom _compare method, just call it __eq__ and reap all the benefits of now being able to use the == operator (including contain testing in lists, container comparisons, etc.).

As a matter of personal preference, though, I'd stay away from that sort-of automatically-generated comparison, and explicitly compare explicit attributes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM