Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Functools -- cmp_to_key

✅ 1. cmp_to_key 是什么?

cmp_to_key 用于把“老式比较函数(cmp 风格)”转换为“新式排序 key 函数”。

Python3 废弃了 cmp 参数,但你有时仍需要:

  • 自定义排序规则
  • 多条件复杂比较
  • 非标准排序逻辑
  • 与 Python2 保持兼容

这时就用:

from functools import cmp_to_key

🟦 2. 为什么需要 cmp_to_key?

Python3 的 sorted() 和 list.sort() 只能用:

  • key=function
  • reverse=True

不能传入 cmp=function。

但有些排序无法用 key 表达,例如:

  • 比较两个元素之间关系
  • 需要看两者的大小变化
  • key 计算无法表示排序规则

例如:

  • 按绝对值排序,但负数优先
  • 复杂多级比较
  • 中文拼音排序
  • 自定义股票排序(如 00 开头优先)
  • 自定义 None / 空值 的排序方式

这些无法用 key 函数表达。

🟩 3. cmp_to_key 最小示例(立刻懂)

from functools import cmp_to_key

def mycmp(a, b):
    if a < b:
        return -1    # a 在前
    if a > b:
        return 1     # b 在前
    return 0         # 相等

nums = [5, 2, 9, 1]
print(sorted(nums, key=cmp_to_key(mycmp)))

输出:

[1, 2, 5, 9]

等效于普通排序,只是使用了自定义比较函数。

🟪 4. cmp_to_key 工作原理

cmp_to_key 会将:

cmp(a, b) -> -1 / 0 / 1

转换为一个 “可比较的 Key 对象”,最终让:

sorted(key=cmp_to_key(...))

能够使用这个 key 的比较逻辑。

简化理解:

cmp -> key

cmp_to_key 把 cmp 封起来,让排序觉得它是一个 key。

🟧 5. 最常用实战示例 ①

按字符串长度排序,但长度相同按字典序排

def mycmp(a, b):
    if len(a) < len(b):
        return -1
    if len(a) > len(b):
        return 1
    return -1 if a < b else (1 if a > b else 0)

lst = ["python", "c", "go", "java"]
print(sorted(lst, key=cmp_to_key(mycmp)))

🟧 6. 最常用实战示例 ②

按股票代码排序(优先 00 -> 60 -> 其他)

def stock_cmp(a, b):
    pri_a = 1 if a.startswith("00") else 2 if a.startswith("60") else 3
    pri_b = 1 if b.startswith("00") else 2 if b.startswith("60") else 3

    if pri_a != pri_b:
        return -1 if pri_a < pri_b else 1
    return -1 if a < b else 1 if a > b else 0

codes = ["300001", "600000", "000001", "601398", "002594"]
print(sorted(codes, key=cmp_to_key(stock_cmp)))

🟧 7. 最常用实战示例 ③

None 排到最后

def none_last(a, b):
    if a is None: return 1
    if b is None: return -1
    return (a > b) - (a < b)

values = [4, None, 2, 9, None, 1]
print(sorted(values, key=cmp_to_key(none_last)))

输出:

[1, 2, 4, 9, None, None]

🟦 8. cmp_to_key 的模板(直接复制用)

def cmp(a, b):
    if a < b:
        return -1
    if a > b:
        return 1
    return 0

sorted_list = sorted(data, key=cmp_to_key(cmp))

多条件比较模板(按重要性排序):

def cmp(a, b):
    # 一级比较
    r = (a["x"] > b["x"]) - (a["x"] < b["x"])
    if r != 0: return r

    # 二级比较
    r = (a["y"] > b["y"]) - (a["y"] < b["y"])
    if r != 0: return r

    # 三级比较
    return (a["z"] > b["z"]) - (a["z"] < b["z"])

🟩 9. cmp_to_key 的高级技巧

多字段排序(字典 / 对象)

def cmp(a, b):
    return (a.id > b.id) - (a.id < b.id) or \
           (a.name > b.name) - (a.name < b.name)

反向排序(自定义)

def reverse_cmp(a, b):
    return (a < b) - (a > b)

中文拼音排序(需要外部库 pypinyin)

🟥 10. 性能注意事项

方法 性能
key 排序 ⭐⭐⭐⭐⭐ 最快
cmp_to_key ⭐⭐ 较慢
手写排序算法 ❌ 不要

如果排序逻辑能用 key 函数表达,一定不要用 cmp_to_key。

🟦 11. 一屏速查表

from functools import cmp_to_key

def cmp(a, b):
    return -1 / 0 / 1

sorted(data, key=cmp_to_key(cmp))

用途:

  • 复杂排序
  • 多字段比较
  • 特殊规则排序
  • 自定义对象比较

优点:

  • 功能强,能表达任意排序逻辑

缺点:

  • 比 key 排序慢
  • 不能用于异步
  • cmp 函数必须返回 -1/0/1