Python排序函数背后的秘密:不只是sort()那么简单

你有没有在写ref="/tag/136/" style="color:#2B406D;font-weight:bold;">Python代码时,随手写下list.sort()或者sorted(list),然后就等着结果出来?看起来很简单,但背后其实藏着不少门道。尤其是在处理大量数据的时候,搞清楚Python排序函数的原理,能帮你省下不少时间。

Python里常用的两个排序方式

平时我们用得最多的就是list.sort()和sorted()。前者是直接修改原列表,后者是生成一个新列表。比如:

numbers = [3, 1, 4, 1, 5]
numbers.sort()
print(numbers)  # 输出 [1, 1, 3, 4, 5]

words = ['banana', 'apple', 'cherry']
new_words = sorted(words)
print(new_words)  # 输出 ['apple', 'banana', 'cherry']

看起来差不多,但性能上有点区别。如果你不在乎原来的顺序,用sort()会更快一点,因为它不额外分配内存。

Timsort:Python排序的核心算法

很多人以为Python用的是快排或者归并排序,其实它用的是Timsort——一种专门为真实世界数据设计的混合排序算法。这名字来自它的作者Tim Peters,2002年被引入Python。

Timsort最厉害的地方是它特别擅长处理“部分有序”的数据。比如你有一堆日志记录,按时间大致是排好序的,但中间插了几条乱序的,Timsort能快速识别出这些有序片段(叫run),然后合并它们。

举个例子,你在整理手机相册时,照片大多是按时间拍的,但偶尔有几张是从别处导入的,打乱了顺序。Timsort就像你一眼看出哪些是连续拍的,先把它们分组,再拼起来,效率比一张张重新排高得多。

稳定排序带来的实际好处

Python的排序是稳定的,意思是相同元素的相对位置不会变。比如你有一个学生成绩表,先按姓名排序,再按成绩排序,那么同分的学生依然保持姓名顺序。

students = [
    ('Alice', 85),
    ('Bob', 85),
    ('Charlie', 90),
    ('David', 85)
]

# 按成绩排序
students.sort(key=lambda x: x[1])
# 结果中,Alice、Bob、David虽然分数一样,但顺序不变

这个特性在做多级排序时特别有用,不用一次性把所有条件都写进去,可以一步步来。

自定义排序:key参数的秘密

很多人知道用key参数,但可能没想过它是怎么工作的。key函数只会被每个元素调用一次,结果缓存起来用于比较。这意味着你可以放心用稍微复杂的函数,比如按字符串长度排:

words = ['python', 'go', 'javascript', 'c']
words.sort(key=len)
print(words)  # ['c', 'go', 'python', 'javascript']

这里len()只对每个单词算一次长度,而不是每次比较都算,所以效率不错。

什么时候该注意排序性能?

如果你只是排几十个元素,随便用。但要是处理上万条数据,比如爬虫抓回来的商品价格、用户行为记录,就得留个心眼。尽量避免在key函数里做耗时操作,比如网络请求或复杂计算。

还有个小技巧:如果要按多个字段排序,别多次调用sort(),用元组作为key更高效:

# 推荐写法
students.sort(key=lambda x: (x[1], x[0]))  # 先按成绩,再按姓名

这样一趟排序搞定,比分开排快得多。

了解这些细节不是为了炫技,而是当你发现程序卡在排序上时,知道往哪改。有时候换种写法,速度能差好几倍。