ActiveState Code

Recipe 576653: Convert a cmp function to a key function


Py3.0 transition aid. The sorted() builtin and the list.sort() method no longer accept a cmp function in Python 3.0. Most cases are easy to convert manually. This recipe handles the remaining cases.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def CmpToKey(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) == -1
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) == 1
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) != 1  
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) != -1
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
    return K

Discussion

In most cases it is easy to convert old-style to new-style. For instance, l.sort(cmp=lambda x, y: cmp(x.lower(), y.lower) converts directly to l.sort(key=str.lower).

However, sometimes there are extensive existing tests that supply custom cmp functions or a user supplied cmp function (part of the exposed API). In those cases, this wrapper can ease the transition. For instance, l.sort(cmp=mycmp) converts to l.sort(key=CmpToKey(mycmp)).

Comments

  1. 1. At 1:56 p.m. on 2 feb 2010, Gabriel Genellina said:

    Warning: the cmp function may return any integer, not just 0, 1, -1. What matters is whether it is greater than, lower than, or equal to 0. __lt__ should be written as:

    mycmp(self.obj, other.obj) < 0
    

    and so on.

    See note (8) at http://docs.python.org/library/stdtypes.html#mutable-sequence-types

Sign in to comment