Да, легко реализовать все с точки зрения, например, __lt__
с классом mixin (или метаклассом, или декоратором класса, если у вас такой вкус).
Например:
class ComparableMixin:
def __eq__(self, other):
return not self<other and not other<self
def __ne__(self, other):
return self<other or other<self
def __gt__(self, other):
return other<self
def __ge__(self, other):
return not self<other
def __le__(self, other):
return not other<self
Теперь ваш класс может определять только __lt__
и умножать наследование от ComparableMixin (после любых других необходимых ему баз, если таковые имеются). Декоратор класса был бы очень похож, просто вставляя аналогичные функции в качестве атрибутов нового класса, который он декорирует (результат может быть микроскопически быстрее во время выполнения при столь же незначительных затратах с точки зрения памяти).
Конечно, если у вашего класса есть какой-то особенно быстрый способ реализации (например, __eq__
и __ne__
), он должен определять их напрямую, чтобы не использовать версии миксина (например, в случае * 1012). *) - на самом деле __ne__
вполне может быть определено так:
def __ne__(self, other):
return not self == other
но в приведенном выше коде я хотел сохранить приятную симметрию, используя только <
;-).
Относительно того, почему __cmp__
пришлось уйти, поскольку у нас было , у нас было __lt__
и друзей, зачем искать другой, совершенно другой способ делать то же самое? Это просто такой большой вес в каждой среде Python (Classic, Jython, IronPython, PyPy, ...). Код, который определенно не будет содержать ошибок, - это код, которого там нет - отсюда и принцип Python, что в идеале должен быть один очевидный способ выполнения задачи (C имеет тот же принцип в «Дух C» раздела ISO, кстати).
Это не значит, что мы делаем все возможное, чтобы запретить вещи (например, почти эквивалентность между миксинами и декораторами классов для некоторых целей), но это определенно означает означает, что нам не нравится для переноса кода в компиляторах и / или средах выполнения, который существует избыточно, просто для поддержки нескольких эквивалентных подходов для выполнения одной и той же задачи.
Дальнейшее редактирование: на самом деле есть еще лучший способ обеспечить сравнение и хеширование для многих классов, в том числе и в вопросе, - метод __key__
, как я упоминал в своем комментарии к вопросу. Поскольку я так и не смог написать для него PEP, вы должны в настоящее время реализовать его с помощью Mixin (& c), если вам это нравится:
class KeyedMixin:
def __lt__(self, other):
return self.__key__() < other.__key__()
# and so on for other comparators, as above, plus:
def __hash__(self):
return hash(self.__key__())
Это очень распространенный случай, когда сравнения экземпляров с другими экземплярами сводятся к сравнению кортежей для каждого с несколькими полями, а затем хеширование должно осуществляться точно так же. Специальный метод __key__
адресов, которые нужны напрямую.