当前位置: 动力学知识库 > 问答 > 编程问答 >

object - 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.

分享给朋友:
您可能感兴趣的文章:
随机阅读: