Вы должны реализовать метод __eq__
:
class MyClass:
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
def __eq__(self, other):
if not isinstance(other, MyClass):
# don't attempt to compare against unrelated types
return NotImplemented
return self.foo == other.foo and self.bar == other.bar
Теперь он выводит:
>>> x == y
True
Обратите внимание, что реализация __eq__
автоматически сделает экземпляры вашего класса недоступными для хранения, что означает, что они не могут быть сохранены в наборах и словах. Если вы не моделируете неизменный тип (т. Е. Если атрибуты foo
и bar
могут изменить значение в течение времени жизни вашего объекта), то рекомендуется просто оставить ваши экземпляры как не подлежащие изменению.
Если вы моделируете неизменный тип, вы также должны реализовать хук datamodel __hash__
:
class MyClass:
...
def __hash__(self):
# necessary for instances to behave sanely in dicts and sets.
return hash((self.foo, self.bar))
Общее решение, такое как идея циклического прохождения __dict__
и сравнения значений, не рекомендуется - оно никогда не может быть по-настоящему общим, поскольку в нем __dict__
могут содержаться несопоставимые или непригодные типы.
NB: знайте, что до Python 3 вам, возможно, придется использовать __cmp__
вместо __eq__
. Пользователи Python 2 также могут захотеть реализовать __ne__
, так как разумное поведение по умолчанию для неравенства (т.е. инвертирование результата равенства) не будет автоматически создано в Python 2.
е-удовлетворяться
источник
return NotImplemented
(вместо повышенияNotImplementedError
). Эта тема освещена здесь: stackoverflow.com/questions/878943/…Вы переопределяете богатые операторы сравнения в вашем объекте.
Как это:
источник
__eq__()
, но только один из__lt__()
,__le__()
,__gt__()
или__ge__()
требуется в дополнение к этому. Исходя из этого, Python может вывести другие методы. Смотритеfunctools
для получения дополнительной информации.functools
модуля, но не работает для стандартных компараторов:MyObj1 != Myobj2
будет работать, только если__ne__()
метод реализован.@functools.total_ordering
декоратора в вашем классе, тогда, как указано выше, вы можете определить просто__eq__
и еще один, а остальные будут полученыРеализуйте
__eq__
метод в своем классе; что-то вроде этого:Изменить: если вы хотите, чтобы ваши объекты сравнивались равными, если и только если они имеют одинаковые словари экземпляров:
источник
self is other
хотите увидеть, являются ли они одним и тем же объектом.AttributeError
. Вы должны вставить строкуif hasattr(other, "path") and hasattr(other, "title"):
(как этот хороший пример в документации по Python).Как резюме:
__eq__
вместо__cmp__
, кроме случаев, когда вы запускаете python <= 2.0 (__eq__
был добавлен в 2.1)__ne__
(должно быть что-то вродеreturn not self.__eq__(other)
илиreturn not self == other
за исключением очень особого случая)Если вы хотите сравнить с объектом, который может быть None, вы должны реализовать его. Переводчик не может угадать это ... (см. Пример ниже)
источник
В зависимости от вашего конкретного случая, вы можете сделать:
Смотрите словарь Python из полей объекта
источник
В Dataclasses в Python 3.7 (и выше) сравнение экземпляров объектов на равенство является встроенной функцией.
Портировать для Dataclasses доступна для Python 3.6.
источник
При сравнении экземпляров объектов
__cmp__
вызывается функция.Если по умолчанию оператор == не работает для вас, вы всегда можете переопределить
__cmp__
функцию для объекта.Редактировать:
Как уже было отмечено, эта
__cmp__
функция устарела с версии 3.0. Вместо этого вы должны использовать методы «богатого сравнения» .источник
Если вы имеете дело с одним или несколькими классами, которые вы не можете изменить изнутри, есть универсальные и простые способы сделать это, которые также не зависят от библиотеки, специфичной для diff:
Самый простой, небезопасный метод для очень сложных объектов
pickle
это очень распространенная библиотека сериализации для объектов Python, и поэтому она может сериализовать практически все, что угодно. В приведенном выше фрагменте я сравниваюstr
из сериализованногоa
изb
. В отличие от следующего метода, этот метод имеет преимущество проверки типов пользовательских классов.Самая большая проблема: из-за специфического упорядочивания и методов кодирования [de / en], они
pickle
могут не дать одинакового результата для одинаковых объектов , особенно при работе с более сложными объектами (например, списками вложенных экземпляров пользовательских классов), как вы часто найдете в некоторых сторонних библиотеках. Для этих случаев я бы рекомендовал другой подход:Тщательный, безопасный для любого объекта метод
Вы можете написать рекурсивное отражение, которое даст вам сериализуемые объекты, а затем сравнить результаты
Теперь не имеет значения, какие у вас объекты, гарантировано глубокое равенство
Количество сопоставимых не имеет значения, а
Мой пример использования для этого заключался в проверке глубокого равенства между разнообразным набором уже обученных моделей машинного обучения в тестах BDD. Модели принадлежали разнообразному набору сторонних библиотек. Конечно, реализация,
__eq__
как и другие ответы здесь, предполагает, что это не вариант для меня.Покрытие всех основ
Вы можете оказаться в ситуации, когда один или несколько сравниваемых пользовательских классов не имеют
__dict__
реализации . Это не часто любыми средствами, но это тот случай подтипа в Random Forest классификатором sklearn в:<type 'sklearn.tree._tree.Tree'>
. Рассматривайте эти ситуации в каждом конкретном случае - например, в частности , я решил заменить содержимое типа «пораженный» на метод, который дает мне репрезентативную информацию об экземпляре (в данном случае,__getstate__
метод). Для таких, второй до последнего рядаbase_typed
сталEdit: ради организации, я заменил последние две строки
base_typed
сreturn dict_from(obj)
, и реализовал действительно родовое отражение , чтобы вместить более неясные LIBS (я смотрю на вас, Doc2Vec)Не забывайте, что ни один из вышеперечисленных методов не дает результатов
True
для разных объектов с одинаковыми парами ключ-значение, но разными порядками ключ / значение, какНо если вы хотите, вы
sorted
все равно можете использовать встроенный метод Python заранее.источник
Я написал это и поместил в
test/utils
модуль в моем проекте. Для случаев, когда это не класс, просто спланируйте его, это обойдет оба объекта и обеспечитЕго большой ... его не сексуально ... но о, бой, это работает!
Вы можете немного почистить его, удалив
_assert
и просто используя обычныйassert
текст, но тогда сообщение, которое вы получаете, когда оно терпит неудачу, очень бесполезно.источник
Вы должны реализовать метод
__eq__
:источник
Ниже работает (в моем ограниченном тестировании) глубокое сравнение двух иерархий объектов. В ней рассматриваются различные случаи, включая случаи, когда сами объекты или их атрибуты являются словарями.
Это очень сложный код, поэтому, пожалуйста, добавьте любые случаи, которые могут не работать в комментариях.
источник
источник
Если вы хотите получить сравнение атрибутов по атрибутам и посмотреть, не сработало ли и где, вы можете использовать следующее понимание списка:
Дополнительным преимуществом здесь является то, что вы можете сжать его на одну строку и войти в окно «Evaluate Expression» при отладке в PyCharm.
источник
Я попробовал начальный пример (см. 7 выше), и он не работал в ipython. Обратите внимание, что cmp (obj1, obj2) возвращает «1» при реализации с использованием двух идентичных экземпляров объекта. Как ни странно, когда я изменяю одно из значений атрибута и перекомпоновываю, используя cmp (obj1, obj2), объект продолжает возвращать «1». (вздох...)
Итак, вам нужно перебрать два объекта и сравнить каждый атрибут с помощью знака ==.
источник
Экземпляр класса по сравнению с == становится неравным. Лучший способ - передать функцию cmp вашему классу, который все сделает.
Если вы хотите сделать сравнение по содержанию, вы можете просто использовать cmp (obj1, obj2)
В вашем случае cmp (doc1, doc2) вернет -1, если содержание будет одинаковым.
источник