Some orderings are naturally pairwise comparisons, and sorting is where Python enforces key functions.
Python's sorted, list.sort, min, max and heapq order items with a key function: a one-argument function computing a sort key for each item, such as key=str.lower or key=lambda u: (u.last, u.first). Each key is computed once, which is efficient.
Some orderings, though, are easier to define by comparing two items: return a negative number if a comes first, positive if b comes first, zero if equal. Python 2 accepted such cmp functions directly; Python 3 doesn't. functools.cmp_to_key(cmp) wraps a comparison function into a key:
sorted(items, key=cmp_to_key(compare))It works by creating wrapper objects whose < calls your function. Each comparison is a Python call, so it's slower than a key function; prefer a key when you can express one.
Classic cases for cmp_to_key:
- Arranging numbers to form the largest concatenation: compare
a+bwithb+a. - Comparisons from external libraries, such as
locale.strcollfor locale-aware string ordering. - Custom version ordering with complex tie-breaking rules.
Remember that Python's sort is stable, so you can sort by a secondary key first and then by the primary key, as an alternative to complex comparisons.
Example
from functools import cmp_to_key
def bigger_concat(a, b):
return (a + b < b + a) - (a + b > b + a) # -1, 0 or 1
nums = ["3", "30", "34", "5", "9"]
print("".join(sorted(nums, key=cmp_to_key(bigger_concat)))) # 9534330
users = [("ann", 31), ("bob", 25), ("cy", 31)]
print(sorted(users, key=lambda u: (-u[1], u[0])))
# [('ann', 31), ('cy', 31), ('bob', 25)]
def by_length_then_alpha(a, b):
if len(a) != len(b):
return len(a) - len(b)
return (a > b) - (a < b)
print(sorted(["pear", "fig", "apple", "kiwi"], key=cmp_to_key(by_length_then_alpha)))
# ['fig', 'kiwi', 'pear', 'apple']Remember
- Sorting uses one-argument key functions in Python 3
cmp_to_keyadapts a pairwise comparison (negative/zero/positive)- Prefer a key function when possible; it's faster
Watch out for
- Passing a comparison function directly as
key=, which compares by the function's return of one argument and fails.