Python 排序指南:sorted() 函数从入门到高级用法全覆盖
0. 写在前面
排序几乎是所有开发者日常都会用到的操作——无论是整理数据报表、筛选Top N结果,还是美化列表输出,高效灵活的排序工具都能帮上大忙。Python 没有让我们自己手写冒泡、快速、归并这些算法,而是直接内置了经过极致优化的稳定排序算法 Timsort(Python 2.3+ 默认实现),并封装成了我们今天要聊的主角:sorted()。
接下来我们会从最基础的整数/字符串排序,一步步进阶到复杂对象、多级排序、性能优化这些场景,全程用可复现的代码示例演示。
1. 基础入门:直接对序列排序
sorted() 的核心优势在于通用性强——它可以接受字符串、列表、元组、生成器等所有可迭代对象,并且永远返回一个新的排好序的列表(原输入不会被修改,这点非常安全!)。
1.1 整数/浮点数排序
默认按数值从小到大(升序)排列:
2. 进阶核心:用 key 自定义排序规则
如果说“默认排序”是入门级操作,那key 参数就是 sorted() 的灵魂——它允许我们传入一个函数,这个函数会作用于输入的每一个元素,生成“排序依据值”,最后 sorted() 只会比较这些依据值的大小。
2.1 简单的数值变形排序
比如开头的例子,按绝对值升序排:
2.2 字符串排序避坑与优化
坑点:默认按 ASCII/Unicode 码值排
英文大小写字母的 Unicode 码值是大写(A-Z: 65-90)小于小写(a-z: 97-122)的,所以直接排序会把大写开头的单词全放前面:
优化:忽略大小写排序
给 key 传 str.lower() 或 str.upper() 就行(选 lower 更通用,比如处理某些非英文字符的大小写):
3. 常用附加:reverse=True 降序排序
想从大到小排?直接加 reverse=True 参数,简单直接:
4. 高级应用:复杂对象排序
开发中我们很少只排纯整数/纯字符串,更多是排元组列表、字典列表、自定义类实例列表这类复杂数据,这时候 key 的优势就更明显了。
先准备一个学生元组列表当测试数据:
4.1 元组列表排序
方案1:自定义普通函数
比如按名字升序(忽略大小写)排:
方案2:用 lambda 表达式简化
如果 key 函数逻辑很简单,一行就能写完,没必要单独定义,直接用 lambda 匿名函数更清爽:
方案3:用 operator 模块提高性能
operator 模块提供了 itemgetter()、attrgetter() 这类函数,专门用来快速获取对象的索引值、属性值,比 lambda 表达式快 10%-20%(大型数据集更明显):
4.2 多级排序
如果遇到“第一优先级按成绩降序,第二优先级按名字升序”这种需求,怎么做?
其实很简单——利用 Python 元组的逐位比较特性(先比第0位,相等再比第1位,以此类推),给 key 返回一个包含多级依据的元组就行:
用 itemgetter() 也能实现多级排序(但只能处理相同方向的优先级,混合升序降序还是要结合 lambda 或分开 reverse):
5. 性能与稳定性小贴士
虽然 Python 的 Timsort 已经非常快了,但在处理百万级以上数据时,还是要注意几个点:
5.1 尽量用 operator 模块的函数
前面提到过,itemgetter()/attrgetter() 比 lambda 快,因为它们是用 C 语言实现的,解释器开销更小。
5.2 尽量避免重复计算 key
如果同一个数据集需要多次排序,不要每次都让 sorted() 重新计算每个元素的 key——可以先预计算 key,保存成元组列表,排序后再提取原数据(这叫“装饰-排序-去装饰”模式,其实 Timsort 内部已经优化过,但手动处理超大列表可能更明显)。
5.3 利用 Timsort 的稳定性
Python 的排序是稳定排序——如果两个元素的 key 完全相等,它们在排序后的相对位置和原列表一致。比如前面的测试数据里,Alice 和 Bob 都是75分,原列表中 Bob 在前,但排序时第二优先级按名字,所以 Alice 跑到前面了;如果去掉第二优先级,原列表的相对位置就会保留:
6. 总结
Python 的 sorted() 是一个功能全面、性能优秀、接口友好的内置排序函数,核心要点如下:
- 通用性强:接受所有可迭代对象,返回新列表(不修改原输入)
- 灵魂参数
key:传入函数自定义排序依据,支持lambda简化、operator提速 - 附加参数
reverse=True:快速实现降序 - 多级排序:利用 Python 元组的逐位比较特性
- 稳定性:相等
key的元素保留原相对位置
掌握了这些,日常开发中99%的排序需求都能轻松搞定~

