from 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).
I do not understand the reasoning why cmp is removed in py3.0
consider this example:
>>> def numeric_compare(x, y): return x - y >>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare) [1, 2, 3, 4, 5]
and now consider this version (recommended and compatible with 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]
The latter is very verbose and the same purpose is achieved in the former with just one line. On another note, I am writing my custom class for which I want to write the __cmp__
method. from my little reading across web, it is recommended to write __lt__,__gt__,__eq__,__le__,__ge__,__ne__ and not __cmp__
Again, why this recommendation? can I not just define __cmp__
making life simpler?
The problem is that the integer values are actually being taken as strings and sorting as if they were strings. The input values first need to be converted before being sorted. Specifically, in the if data: portion, specifying to append data as an int to the list solves the problem and the sorted or .
sort() and sorted() in python are “stable sorts”, meaning that it'll preserve the existing order when faced with a tie.
The __cmp__() special method is no longer honored in Python 3. In Python 2, __cmp__(self, other) implemented comparison between two objects, returning a negative value if self < other , positive if self > other , and zero if they were equal.
The Python sorted() uses the Timsort algorithm which is a hybrid sorting algorithm, derived from merge sort and insertion sort.
For two objects a
and b
, __cmp__
requires that one of a < b
, a == b
, and a > b
is true. But that might not be the case: consider sets, where it's very common that none of those are true, e.g. {1, 2, 3}
vs {4, 5, 6}
.
So __lt__
and friends were introduced. But that left Python with two separate ordering mechanisms, which is kind of ridiculous, so the less flexible one was removed in Python 3.
You don't actually have to implement all six comparison methods. You can use the @total_ordering
decorator and only implement __lt__
and __eq__
.
edit: Also note that, in the case of sorting, key
functions can be more efficient than cmp
: in the example you gave, Python may have to call your Python comparison function O(n²) times. But a key
function only needs to be called O(n) times, and if the return value is then a builtin type (as it very often is), the O(n²) pairwise comparisons go through C.
cmp
was removed because the key
attribute to .sort()
and sorted()
is superior in most cases. It was a hold-over from C more than anything, and was confusing to boot. Having to implement a separate __cmp__
method next to the rich comparison operators (__lt__
, __gt__
, etc.) was befuddling and unhelpful.
You can always use functools.cmp_to_key()
to adapt an existing cmp
function.
Your specific example could have been implemented without a key
function, of course, as integers are already orderable; just add reverse=True
.
For custom classes, use the @functools.total_ordering
decorator to expand a __eq__
and one comparison operator method (e.g. __lt__
, or __gt__
, etc.) into a full ordering implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With