In Python, both list.sort
method and sorted
built-in function accepts an optional parameter named key
, which is a function that, given an element from the list returns its sorting key.
Older Python versions used a different approach using the cmp
parameter instead, which is a function that, given two elements from the list returns a negative number if the first is less than the second, zero if there are equals and a positive number if the first is greater. At some point, this parameter was deprecated and wasn't included in Python 3.
The other day I wanted to sort a list of elements in a way that a cmp
function was much more easier to write than a key
one. I didn't wanted to use a deprecated feature so I read the documentation and I found that there is a funtion named cmp_to_key
in the functools
module which, as his name states, receives a cmp
function and returns a key
one... or that's what I thought until I read the source code (or at least an equivalent version) of this high level function included in the docs
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
Despite the fact that cmp_to_key
works as expected, I get surprised by the fact that this function doesn't return a function but a K
class instead. Why? How does it work? My guess it that the sorted
function internally checks whether cmp is a function or a K class or something similar, but I'm not sure.
P.S.: Despite this weirdness, I found that K class is very useful. Check this code:
from functools import cmp_to_key
def my_cmp(a, b):
# some sorting comparison which is hard to express using a key function
class MyClass(cmp_to_key(my_cmp)):
...
This way, any list of instances of MyClass can be, by default, sorted by the criteria defined in my_cmp