First, if you have not read the Sorting HOWTO , be sure to read this; this explains a lot that may not be reasonable at first.
For your first example, two IPv4 addresses, the answer is pretty simple.
To compare two addresses, you need to do one of the obvious things: convert them both from four-dot strings and from four strings, and then simply compare the tuples:
def cmp_ip(ip1, ip2): ip1 = map(int, ip1.split('.')) ip2 = map(int, ip2.split('.')) return cmp(ip1, ip2)
Better still is to convert them to some kind of object that represents an IP address and has comparison operators. In 3.4+, stdlib has such an object inline; let it look 2.7 too:
def cmp_ip(ip1, ip2): return cmp(ipaddress.ip_address(ip1), ipaddress.ip_address(ip2))
Obviously, this is even simpler than key functions:
def key_ip(ip): return map(int, ip.split('.')) def key_ip(ip): return ipaddress.ip_address(ip)
For your second example of the mention of ham radio operators: in order to write the cmp function, you should be able to split each ham address into letters, numbers, letters, then compare the numbers, then compare the first letters, then compare the two letters. To write the key function, you must be able to split the ham address into letters, numbers, letters, and then return a tuple (numbers, first letters, letters). Again, the key function is actually simpler, not harder.
And indeed, this applies to most of the examples that anyone could come up with. The most complex comparisons ultimately boil down to a complex transformation into a sequence of parts, and then to a simple lexicographic comparison of this sequence.
This is why cmp functions are deprecated in 2.4 and permanently removed in 3.0.
Of course, there are some cases where the cmp function is easier to read - most of the examples that people try to come up with are erroneous, but there are some. And there is also code that has been running for 20 years, and no one wants to rethink it under new conditions without any benefit. For these cases, you have cmp_to_key .
In fact, another reason for cmp was obsolete, on top of this and possibly a third.
In Python 2.3, types had the __cmp__ method, which was used to process all statements. In 2.4, they replaced the six methods __lt__ , __eq__ , etc. This allows you to increase flexibility, for example, you can have types that are not fully ordered. So, 2,3 when comparing a < b , it actually did a.__cmp__(b) < 0 , which pretty obviously displays the cmp argument. But in version 2.4+ a < b does a.__lt__(b) , which is not. This has confused many people over the years and removed both the __cmp__ and cmp arguments to sort functions removed from this confusion.
Meanwhile, if you read HOWTO Sort, you will notice that before we had cmp , the only way to do this is to decorate-sort-undecorate (DSU). Note that the blindly explicit idea of ββa good key function for good DSU sorting and vice versa, but this is definitely not obvious with the cmp function. I donβt remember anyone explicitly mentioning this on the py3k list, but I suspect that people may have had this in their heads when deciding whether to kill cmp permanently.