Почему параметр cmp удален из sort/sorted в Python3.0?
из python wiki:
In Py3.0, the cmp parameter was removed entirely (as part of a larger effort to simplify and unify the language, eliminating the conflict between rich comparisons and the __cmp__ methods).
Я не понимаю причины, почему cmp удаляется в py3.0
рассмотрим этот пример:
>>> def numeric_compare(x, y):
return x - y
>>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare)
[1, 2, 3, 4, 5]
и теперь рассмотрим эту версию (рекомендуется и совместима с 3.0):
def cmp_to_key(mycmp):
'Convert a cmp= function into a key= function'
class K(object):
def __init__(self, obj, *args):
self.obj = obj
def __lt__(self, other):
return mycmp(self.obj, other.obj) < 0
def __gt__(self, other):
return mycmp(self.obj, other.obj) > 0
def __eq__(self, other):
return mycmp(self.obj, other.obj) == 0
def __le__(self, other):
return mycmp(self.obj, other.obj) <= 0
def __ge__(self, other):
return mycmp(self.obj, other.obj) >= 0
def __ne__(self, other):
return mycmp(self.obj, other.obj) != 0
return K
>>> sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric))
[5, 4, 3, 2, 1]
Последнее очень многословно, и та же цель достигается в первом только с одной строкой. В другой заметке я пишу свой собственный класс, для которого я хочу написать метод __cmp__
. из моего небольшого чтения через Интернет, рекомендуется написать __lt__,__gt__,__eq__,__le__,__ge__,__ne__ and not __cmp__
Опять же, почему эта рекомендация? могу ли я просто определить __cmp__
сделать жизнь проще?
Ответы
Ответ 1
Для двух объектов a
и b
, __cmp__
требуется, чтобы один из a < b
, a == b
и a > b
был истинным. Но это может быть не так: рассмотрите множества, где очень распространено, что ни одно из них не является истинным, например. {1, 2, 3}
vs {4, 5, 6}
.
Итак, __lt__
и друзья были представлены. Но это оставило Python с двумя отдельными механизмами упорядочения, что довольно смешно, поэтому менее гибкий был удален в Python 3.
На самом деле вам не нужно реализовывать все шесть методов сравнения. Вы можете использовать @total_ordering
декоратор и использовать только __lt__
и __eq__
.
edit: Также обратите внимание, что в случае сортировки функции key
могут быть более эффективными, чем cmp
: в примере, который вы дали, Python, возможно, придется вызывать функцию сравнения Python O (n²) раз. Но функция key
должна быть вызвана только O (n) раз, а если возвращаемое значение является встроенным (как это часто бывает), то парные сравнения O (n²) проходят через C.
Ответ 2
cmp
был удален, потому что атрибут key
для .sort()
и sorted()
превосходит в большинстве случаев. Это было больше, чем когда-либо, и сбивало с толку ботинок. Необходимость реализовать отдельный метод __cmp__
рядом с богатыми операторами сравнения (__lt__
, __gt__
и т.д.) Была путаной и бесполезной.
Вы можете всегда использовать functools.cmp_to_key()
для адаптации существующей функции cmp
.
Ваш конкретный пример мог быть реализован без функции key
, конечно, поскольку целые числа уже заказываются; просто добавьте reverse=True
.
Для пользовательских классов используйте @functools.total_ordering
decorator, чтобы развернуть __eq__
и один метод оператора сравнения (например, __lt__
, или __gt__
и т.д.) в реализацию полного упорядочения.