2013-12-10 26 views
1

我在寻找比较两个类实例的内容的最有效的方式的最有效方式。我有一个包含这些类实例的列表,并且在追加到列表之前,我想确定它们的属性值是否相同。这对大多数人来说可能看起来微不足道,但在仔细阅读这些论坛之后,我并没有明确自己想要做什么。另请注意,我没有编程背景。在python比较两个类实例的内容

这是我到目前为止有:

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)) 

然后加入到我的清单,我会做一些事情,如:

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

if not found: myList.append(newInstance) 

但我不清楚这是否是最有效的或者比较同一类的实例内容的python-ic方法。

+0

你应该把它们放在一个集合中,并在你的类中实现'__hash__'和'__eq__'。 – khachik

回答

6

实施a __eq__ special method改为:

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__ 

现在你可以使用:

if newInstance in myList: 

和Python将自动使用__eq__特殊的方法来测试是否相等。

在我的版本我保留在一组有限的属性来传递的能力:

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

但使用all(),以确保我们只测试尽可能是必要的。

请注意,我们返回NotImplemented,一个特殊的单独的对象发出信号,表明比较不支持; Python会问问其他对象,如果它也许是支持,而不是平等的测试这种情况。

4

您可以实现comparison magic method__eq__(self, other)为您的类,然后简单地做

if instance == newInstance: 

正如你显然不知道什么属性的情况下都会有,你可以这样做:

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

你的方法有一个重大缺陷:如果您有两个来自BaseObject派生的类参考周期,你的比较将永远不会结束,并与堆栈溢出死亡。

此外,不同类的,但具有相同的属性值的两个对象的比较结果为相等的。简单的例子:无属性BaseObject任何实例将比较结果为相等的子类BaseObject无属性的任何实例(因为如果issubclass(C, B)aC的实例,则返回isinstance(a, B)True)。

最后,而不是编写自定义_compare方法,只是把它__eq__牟取现在能够使用==运营商(包括含有清单测试,容器的比较等)的所有优势。

尽管个人喜好,我会远离那种自动生成的比较,并明确地比较明确的属性。

+0

*两个不同类的对象,但具有相同的属性值比较相等*:这绝对是明显*不真实*。不同类别的实例永远不会相同。即使OP版本首先执行'isinstance()'测试,'object()'也不会通过该测试。 –

+0

哎呀,我的坏,我错过了''isinstance''检查。在咖啡有时间开始之前不应评论这些事情。然而,不同类别的实例会返回“None”而不是0,这可能是也可能不是您想要的。 –

+0

你真正想要的是为这些情况返回'NotImplemented',这样Python就会查找'second .__ eq __(first)'。 –