Сравнение экземпляров объектов в Python по атрибутам
Быстрый ответ
Для сравнения объектов на равенство, исходя из их атрибутов, необходимо переопределить метод __eq__
. Это хороший способ, особенно когда требуется сравнивать все атрибуты объекта:
class MyClass:
def __init__(self, *args):
self.attributes = args
def __eq__(self, other):
return isinstance(other, MyClass) and all(getattr(self, attr) == getattr(other, attr) for attr in vars(self))
obj1 = MyClass(1, 'a')
obj2 = MyClass(1, 'а')
print(obj1 == obj2) # Вернёт "True", если объекты равны
Данный подход эффективен, масштабируем и легко поддерживается, особенно при наличии большого количества атрибутов у класса.
Подробнее о __eq__
Перед сравнением атрибутов убедитесь, что типы сравниваемых объектов совпадают:
if not isinstance(other, self.__class__):
return NotImplemented
Если ваши объекты неизменяемые, то реализуйте __hash__
для возможности их использования в качестве ключей в словарях или элементов множеств:
def __hash__(self):
return hash(tuple(sorted(self.__dict__.items())))
За пределами __eq__
Полное сравнение
Для полноценной реализации операций сравнения определите методы __lt__
, __le__
, __gt__
и __ge__
.
Глубокое сравнение
При необходимости сравнения объектов с вложенными атрибутами можно воспользоваться функцией pickle.dumps
:
import pickle
def __eq__(self, other):
return isinstance(other, MyClass) and pickle.dumps(self) == pickle.dumps(other)
Dataclasses: новый подход к работе со структурами
С Python 3.7 стали доступными dataclasses, которые автоматизируют сравнение атрибутов и многие другие операции:
from dataclasses import dataclass
@dataclass
class MyClass:
foo: int
bar: str
Важность выбора версии Python
Особенности Python 2
В Python 2 для полноценного сравнения объектов необходимо также определить метод __ne__
:
def __ne__(self, other):
return not self.__eq__(other)
В Python 2 присутствует метод __cmp__
, предназначенный для организации сравнения:
def __cmp__(self, other):
if isinstance(other, MyClass):
# тело метода
Визуализация
Сравнение объектов можно представить как подбор подходящих элементов пазла:
Объект A (🧩): {цвет: 'красный', форма: 'квадрат', размер: 'средний'}
Объект B (🧩): {цвет: 'красный', форма: 'квадрат', размер: 'средний'}
Совпадают ли все атрибуты?
🧩==🧩: [цвет ✅, форма ✅, размер ✅]
# Отлично! Объекты A и B равны.
Сравнение неупорядоченных коллекций
Если атрибуты представлены в виде неупорядоченных коллекций, используйте сортировку:
class MyClassWithList:
def __init__(self, elements):
self.elements = elements
def __eq__(self, other):
return isinstance(other, MyClassWithList) and sorted(self.elements) == sorted(other.elements)
Разнообразие при сравнении
Для сравнения объектов с одинаковыми атрибутами, но представленными различными типами данных, используйте приведение типов:
class MyClassWithString:
def __init__(self, num_str):
self.num_str = num_str
def __eq__(self, other):
return str(self) == str(other)
Полезные материалы
- 3. Data model — Python 3.12.2 documentation – описание метода
__eq__
для сравнения объектов в Python. - Python '!=' Is Not 'is not': Comparing Objects in Python – Real Python – обсуждение различия между
is
и==
в Python. - dataclasses — Data Classes — Python 3.12.2 documentation – документация о классах данных в Python 3.7 и новее.
- attrs 23.2.0 documentation – библиотека для упрощения сравнения объектов.
- Operator Overloading in Python – GeeksforGeeks – подробно о переопределении операторов в Python для сравнения созданных объектов.