There is a pure-Python implementation available in functools.py
, reproduced below:
def cmp_to_key(mycmp):
"""Convert a cmp= function into a key= function"""
class K(object):
__slots__ = ['obj']
def __init__(self, obj):
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
__hash__ = None
return K
The functools.KeyWrapper
instances you've seen returned are not actually from this Python code, but a C implementation which you can find in _functoolsmodule.c
. The technique is similar: it needn't return some kind of scalar value such as an integer, it only has to return things which can be compared with eachother. It achieves that just by defining the necessary comparison operators, which use the cmp
function provided by the caller.
I thought that the return value would give me some kind of a value that could be used as a sort key. Why am I getting a function Wrapper?
It's not a value that can be used as a sort key, it is the sort key.
Inverting the normal ordering of integers or strings, for example:
def cmp_to_key(mycmp):
class K:
def __init__(self, obj):
self.obj = obj
def __lt__(self, other):
return mycmp(self.obj, other.obj) < 0
return K
def cmp(x, y):
return 1 if x < y else 0 if x == y else -1
key = cmp_to_key(cmp)
Demo:
>>> "foo" < "bar"
False
>>> key("foo") < key("bar")
True
>>> sorted([1,2,3], key=key)
[3, 2, 1]