• How did Python3 lose cmp in sorted?

During video code review veky's showing how cmd argument has been removed in Python3, and why and how It can be replaced.

We mentioned using sort function inside the solution for mission "Bigger Together" from kurosawa4434.

Interface of the function sort was simplified in Python3 comparing to Python2.

In Python2 you could sort iterable not only by specifying a key, but also by specifying a function for cmp argument for sorted function. The function takes two items from iterables as arguments, and should return a number. If the number is positive then the first given value should be before the second one, if negative - then the opposite.

>>> sorted(some_iterable, cmp=lambda first, second: -1 if first < second else 1)

You can also use 0, if two items are the same and the order is not important.

Then Guido mentioned that people more often use compare function like this

>>> def compare(a, b):
        return (a>b) - (a>> compare(3, 6)
<<< -1

>>> compate(6, 2)
<<< 1

And if you want to sort lists by their length you can use

>> sorted(lists, cmp=lambda a,b: compare(len(a), len(b))

What if we could get rid of this compare-madness and just specify the kеy

>>> sorted(lists, key=lambda a:len(a))

It is easier to write, and it should be faster since you just need to calculate one element only once, when in case of cmp you need to calculate a value with other elements.

So, the solution of one of the CheckiO missions' where you need to sort list by absolute values can simply look like this

>>> sorted(values, key=abs)

Simple, right?

But why wouldn't they leave two interfaces, so I can choose for myself which one I want to use? Because they want to simplify language and give you less reasons to shot yourself in a leg.

That's why Python3 is much simpler this way, but a bit harder in a way that you should really understand what you are doing.

The same story we have with reduce function in Python, because Python3 doesn't have reduce as a builtin function, but as a part of core module

>>> from functools import reduce

But in case you really-really need cmp for sorted function, Guido leaves an adaptor for you.

>>> from functools import cmp_to_key

So you can use it like kurosawa4434 did in his solutions

>>> sorted(map(str, ints), key=cmp_to_key(lambda a, b: int(a+b)-int(b+a)))

The implementation of the function cmp_to_key only shows how powerful and flexible Python is.

I leave the source here

 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

As you can see, cmp_to_key generates a class K using compare function mycmp. The result of key-function instance of the class K, which will use its own methods __lt__, __gt__, __eq__, __le__ and __ge__ to compare K-objects between each other. And the function mycmp will be used for this comparison.

That is it for now. In the next article we will explain what this __slots__ means in the K class.

Become Awesome

  • No Ads
  • No Limits
  • More Content

Welcome to CheckiO - games for coders where you can improve your codings skills.

The main idea behind these games is to give you the opportunity to learn by exchanging experience with the rest of the community. Every day we are trying to find interesting solutions for you to help you become a better coder.

Join the Game