2013-12-10 2 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) и a является экземпляр C, а затем возвращается isinstance(a, B)True).

Наконец, вместо того, чтобы писать метод пользовательских _compare, просто назвать его __eq__ и пожинать все преимущества в настоящее время в состоянии использовать оператор == (в том числе содержать тестирование в списках, контейнеры сравнение и т.д.).

Как бы то ни было, я бы избегал такого рода автоматически сгенерированного сравнения и явно сопоставлял явные атрибуты.

+0

* два объекта разных классов, но с одинаковыми значениями атрибутов, сравниваются как равные *: это абсолютно, явно * не верно *. Экземпляры разных классов никогда не равны. Даже версия OP сначала выполняет проверку 'isinstance()', а 'object()' не будет проходить этот тест. –

+0

Упс, я плохо, я пропустил проверку '' isinstance''. Не следует комментировать эти вещи, прежде чем кофе успеет зайти. Однако экземпляры разных классов возвращают '' None'' вместо 0, что может быть или не быть тем, что вы хотите. –

+0

В самом деле, вы хотите вернуть 'NotImplemented' для этих случаев, чтобы Python искал' second .__ eq __ (first) '. –

Смежные вопросы