python多键排序应直接使用sorted()或list.sort()配合tuple比较,避免造轮子;核心是key返回元组,利用python元组比较规则实现多级顺序,注意数值降序用负号、字符串降序用reverse=true,字段缺失需默认值处理,优先用operator.itemgetter/attrgetter提升性能与可读性。

Python 内置的 sorted() 和 list.sort() 已经原生支持多键排序,不需要额外封装“高级列表结构”——强行造轮子反而容易破坏稳定性、引入隐式 bug。
多键排序的本质是 tuple 比较
Python 对元组的比较规则天然适配多级排序:先比第一个元素,相等再比第二个,依此类推。所有多键逻辑都建立在这个基础上。
实操建议:
- 用
key=lambda x: (x.age, -x.score, x.name)实现“年龄升序 → 分数降序 → 姓名升序” - 注意负号取反仅适用于数值;字符串降序要用
reverse=True配合正向 key,或写成key=lambda x: (-x.age, x.score, x.name)(仅当 age 可负时需谨慎) - 字段缺失时会抛
TypeError,可用getattr(x, 'score', 0)或operator.attrgetter('age', 'score')+ 默认值处理
用 operator.itemgetter 或 attrgetter 提升可读性与性能
相比 lambda,operator.itemgetter 和 operator.attrgetter 更快且语义清晰,尤其适合按字段名/索引排序。
常见错误现象:
- 误写
itemgetter('name', 'age')但对象是字典却用了attrgetter—— 类型不匹配直接报AttributeError - 对嵌套结构(如
x.info['level'])强行用itemgetter,应改用 lambda 或自定义函数 -
attrgetter不支持默认值,字段不存在就崩,必须配合hasattr或 try/except
示例:sorted(data, key=attrgetter('status', 'updated_at'))
稳定排序下多条件不能靠多次 sort 实现
Python 的排序是稳定的,但“先按 A 排,再按 B 排” ≠ “按 (A,B) 多键排”。后者才是真多级,前者会覆盖前序顺序。
使用场景:
- 错误做法:
data.sort(key=lambda x: x.score); data.sort(key=lambda x: x.grade)—— 最终只按 grade 有序 - 正确做法:单次排序,key 返回 tuple,如
key=lambda x: (x.grade, x.score) - 若必须分步(比如动态加条件),应构建复合 key 函数,而非链式调用
sort()
自定义类想支持 .sort() 需重载 __lt__?别这么做
给自定义容器类加 __lt__ 并不能让 list.sort() 自动识别你的多键逻辑——它只作用于你类的实例之间比较,而 sort() 默认还是看 key 函数返回值。
容易踩的坑:
- 以为实现
__lt__就能省掉 key 参数,结果排序完全不符合预期 - 在
__lt__里硬编码排序逻辑,导致同一类对象无法按不同维度复用 - 忽略
functools.total_ordering的约束,漏实现其他比较方法引发不可预测行为
真正需要封装时,优先考虑函数式组合:写一个 make_sort_key(fields, reverses) 工厂函数,而不是继承 list 或重载魔术方法。
多键排序的复杂点不在语法,而在字段类型一致性、空值处理和业务语义绑定——这些没法靠“高级结构”自动解决,得在 key 函数里显式表达清楚。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











