Чтобы сделать объекты пользовательского класса сопоставимыми, достаточно ли определить только несколько членов из семейств `__eq__` и` __lt__`? - PullRequest
0 голосов
/ 26 августа 2018

Допустим, у меня есть класс, члены которого я хочу сравнить с обычными операторами ==, <, <=, > и >=.

Как яПонимаете, это может быть достигнуто путем инициализации определяющего магического метода __cmp__(a, b), который возвращает -1 (a < b), 0 (a == b) или 1 (a > b).

Кажется, что __cmp__ устарел с Python 3 в пользу определения __eq__, __lt__, __le__, __gt__ и _ge__ методов отдельно.

Я определил __eq__и __lt__ при условии, что значения по умолчанию для __le__ будут выглядеть примерно так: return a == b or a < b.Кажется, что это не так со следующим классом:

class PQItem:
    def __init__(self, priority, item):
        self.priority = priority
        self.item = item

    def __eq__(self, other):
        return isinstance(other, PQItem) and self.priority == other.priority

    def __lt__(self, other):
        return isinstance(other, PQItem) and self.priority < other.priority

class NotComparable:
    pass

x = NotComparable()
y = NotComparable()
# x < y gives error

И я получаю такой результат:

>>> PQItem(1, x) == PQItem(1, y)
True
>>> PQItem(1, x) < PQItem(1, y)
False
>>> PQItem(1, x) <= PQItem(1, y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: PQItem() <= PQItem()

Это заставило меня заключить, что мне придется определить всеметоды магии сравнения вручную, чтобы сделать класс сопоставимым.Есть ли лучший способ?

Почему __cmp__ устарела?Похоже, гораздо приятнее справиться с этим

1 Ответ

0 голосов
/ 26 августа 2018

Для двух объектов a и b, __cmp__ требует, чтобы один из a < b, a == b и a > b имел значение true.Но это может быть не так: рассмотрим множества, где очень часто ни один из этих не является истинным, например, {1, 2, 3} против {4, 5, 6}.

Так что __lt__ и тому подобноебыли введены.Но это оставило Python с двумя отдельными механизмами упорядочения, что довольно смешно, поэтому менее гибкий был удален в Python 3.

На самом деле вам не нужно реализовывать все шесть методов сравнения.Вы можете использовать декоратор класса functools.total_ordering, чтобы помочь определить остальные магические методы сравнения:

from functools import total_ordering
@total_ordering
class PQItem:
    def __init__(self, priority, item):
        self.priority = priority
        self.item = item

    def __eq__(self, other):
        return isinstance(other, PQItem) and self.priority == other.priority

    def __lt__(self, other):
        return isinstance(other, PQItem) and self.priority < other.priority
...