Why is cmp( ) useful?

Trivalued comparators are very useful when sorting. You don't just want to know whether two elements are equal; you also want to know their relative order so that you know how to rearrange them to move closer to a sorted list. This is why C (strcmp) and Perl (cmp) both have similar operations (in those cases for strings, but it's the same idea).


For sorting sequences of items. When you are sorting a list of items you only need to know one item is greater or less than another item.

More info here: http://wiki.python.org/moin/HowTo/Sorting/#The_Old_Way_Using_the_cmp_Parameter


I don't really get what does it mean sign of the difference of two numbers.

This means: take the difference, and then the sign of that difference. For example, if x and y are two numbers:

  • x < y => x - y < 0 and the function returns -1.
  • x == y => x - y == 0 and the function returns 0.
  • x > y => x - y > 0 and the function returns 1.

For more information on three-way comparisons, see Wikipedia.


Why cmp( ) is useful?

It isn't very useful, which is why it was deprecated (the builtin cmp is gone and builtin sorts no longer accept one in Python 3). Rich comparison methods supplanted it:

object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)

This allows the < symbol (and other symbols) to be overloaded comparison operators, enabling, for example, subset and superset comparisons of set objects.

>>> set('abc') < set('cba')
False
>>> set('abc') <= set('cba')
True
>>> set('abc') == set('cba')
True
>>> set('abc') >= set('cba')
True
>>> set('abc') > set('cba')
False

while it could enable the above, cmp wouldn't allow the following:

>>> set('abc') == set('bcd')
False
>>> set('abc') >= set('bcd')
False
>>> set('abc') <= set('bcd')
False

Toy usage for cmp

Here's an interesting usage which uses its result as an index (it returns -1 if the first is less than the second, 0 if equal, and 1 if greater than):

def cmp_to_symbol(val, other_val):
    '''returns the symbol representing the relationship between two values'''
    return '=><'[cmp(val, other_val)]

>>> cmp_to_symbol(0, 1)
'<'
>>> cmp_to_symbol(1, 1)
'='
>>> cmp_to_symbol(1, 0)
'>'

According to the docs, you should treat cmp as if it wasn't there:

https://docs.python.org/3/whatsnew/3.0.html#ordering-comparisons

cmp removed, equivalent operation

But you can use this as the equivalent:

(a > b) - (a < b)

in our little toy function, that's this:

def cmp_to_symbol(val, other_val):
    '''returns the symbol representing the relationship between two values'''
    return '=><'[(val > other_val) - (val < other_val)]

Tags:

Python