2013-12-10 24 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)'。 –