Программа курса:
Методы для сравнения объектов

В этой лекции мы научимся сравнивать объекты пользовательских классов между собой. По умолчанию экземпляры классов в Python не поддерживают операции сравнения. Если попробовать сравнить два объекта через операторы ==, !=, >, <, >=, или <=, Python выбросит исключение.
Пример ошибки при попытке сравнения двух объектов класса Shape с использованием оператора >:
TypeError: '>' not supported between instances of 'Shape' and 'Shape'
Причина ошибки в том, что для выполнения операций сравнения в классе должны быть определены специальные магические методы. Для каждого оператора существует свой метод, как показано в таблице ниже:
| Оператор | Магический метод |
|---|---|
== | __eq__ |
!= | __ne__ |
< | __lt__ |
<= | __le__ |
> | __gt__ |
>= | __ge__ |
Когда вы сравниваете объекты через A == B, Python на самом деле вызывает A.__eq__(B).
Реализация магических методов для сравнения
Чтобы класс поддерживал сравнение, достаточно реализовать соответствующие методы. Рассмотрим пример, в котором мы создадим класс Shape и добавим в него методы для проверки на равенство == и на меньшее <.
class Shape:
def __init__(self, area):
self.area = area
def __eq__(self, other):
if isinstance(other, Shape):
return self.area == other.area
return False
def __lt__(self, other):
if isinstance(other, Shape):
return self.area < other.area
return False
Теперь объекты класса Shape могут сравниваться друг с другом с помощью операторов == и <. Например:
s1 = Shape(30)
s2 = Shape(45)
assert s1 == Shape(30) # True
assert s1 < s2 # True
assert s1 == s2 # False
Пример сравнения с числами
Также можно реализовать логику, чтобы объекты сравнивались не только с другими объектами класса, но и с числами:
class Shape:
def __init__(self, area):
self.area = area
def __lt__(self, other):
if isinstance(other, Shape):
return self.area < other.area
elif isinstance(other, (int, float)):
return self.area < other
return NotImplemented
s = Shape(25)
assert s < 30 # True
assert s < 10 # False
Но если попытаться сравнить объект с числом через >, возникнет ошибка:
TypeError: '>' not supported between instances of 'Shape' and 'int'
Механизм обратного сравнения
Операции сравнения являются бинарными, то есть в них участвуют два операнда. Python вызывает метод сравнения у левого операнда. Например, при выражении A > B Python вызывает метод A.__gt__(B). Если метод __gt__ не определен в классе A, Python попробует переставить операнды и изменить оператор на противоположный, вызвав метод B.__lt__(A).
Таким образом, если в классе Shape метод __gt__ не реализован, а метод __lt__ есть, то при сравнении двух объектов s1 > s2 Python фактически выполнит операцию s2.__lt__(s1).
Однако, если мы пытаемся сравнить объект с числом через >, Python попытается вызвать other.__lt__(self). Но типы int и float не умеют сравниваться с пользовательскими объектами, поэтому возникнет ошибка:
s > 5 # TypeError: '>' not supported between instances of 'Shape' and 'int'
Как избежать дублирования кода
Для каждого из шести операторов сравнения в Python есть соответствующий магический метод. Тем не менее, реализация всех этих методов может привести к избыточности. Чтобы этого избежать, достаточно реализовать только три метода, поскольку они противоположны друг другу:
| Метод сравнения | Противоположный метод |
|---|---|
__eq__ | __ne__ |
__lt__ | __gt__ |
__le__ | __ge__ |
Для примера реализуем методы __eq__, __lt__ и __le__. Оператор <= можно выразить через комбинацию операторов < и ==, так как <= буквально означает «меньше или равно».
class Shape:
def __init__(self, area):
self.area = area
def __eq__(self, other):
if isinstance(other, Shape):
return self.area == other.area
return False
def __lt__(self, other):
if isinstance(other, Shape):
return self.area < other.area
elif isinstance(other, (int, float)):
return self.area < other
return NotImplemented
def __le__(self, other):
return self == other or self < other
Полный пример с тестами
Теперь наш класс поддерживает все необходимые операторы сравнения:
s1 = Shape(30)
s2 = Shape(45)
assert s1 == Shape(30) # True
assert s1 != s2 # True
assert s1 < s2 # True
assert s1 <= s2 # True
assert s2 > s1 # True
assert s2 >= Shape(45) # True
assert s1 <= 35 # True
assert s2 > 40 # True
В этом уроке мы научились добавлять поддержку операций сравнения в пользовательские классы, используя магические методы. Мы увидели, как эффективно реализовать три из шести операторов сравнения и избежать дублирования кода.
Ограниченный доступ
Вы можете только просматривать лекции, так как данный курс является платным. Чтобы получить полный доступ к курсу, приобретите его!