1
2
3
4
5
6
7
作者:李晓辉

联系方式:

1. 微信:Lxh_Chat

2. 邮箱:939958092@qq.com
  1. Python 系列(一) 从零开始认识 Python,入门其实没那么难
  2. Python 系列(二) 学 Python 的第一步,把开发环境搭建好
  3. Python 系列(三) 基础语法避坑指南,缩进、大小写、续行与注释
  4. Python 系列(四) Python 输入输出详解,print()、input() 与常见避坑指南
  5. Python 系列(五) 数值类型与运算符详解,整除、浮点精度与进制转换实战
  6. Python 系列(六) 字符串处理实战,查找、替换、切片与日志分析
  7. Python 系列(七) 类型转换详解,int()、float()、str() 与金额计算避坑
  8. Python 系列(八) Python 流程控制入门,掌握 if、elif 和 else
  9. Python 系列(九) Python 逻辑运算符详解,and、or、not 一篇搞懂
  10. Python 系列(十) while、for 循环实战,彻底搞懂 range、break 与 continue
  11. Python 系列(十一) list、tuple、set、dict,到底该怎么选?
  12. Python 系列(十二) List 列表实战,搞定数据增删改查与批量处理
  13. Python 系列(十三) Tuple 元组实战,搞懂不可变特性与 enumerate() 遍历
  14. Python 系列(十四) Set 集合实战,搞定数据去重与集合运算
  15. Python 系列(十五) Dict 字典详解,掌握快速查找与键值操作
  16. Python 系列(十六) sort() 和 sorted() 详解,掌握数据排序技巧
  17. Python 系列(十七) 自定义函数入门,让重复代码一次编写多次使用
  18. Python 系列(十八) 函数参数详解,搞懂位置参数、关键字参数和默认参数
  19. Python 系列(十九) 从 *args 到 **kwargs,让函数调用更灵活

前面我们学习了 Python 中的 List 列表、Tuple 元组、Set 集合和 Dict 字典。

List 可以保存一组有序数据,Tuple 适合保存不希望被修改的数据,Set 擅长去重和集合运算,Dict 则可以通过键快速查找对应的值。

不过,在实际工作中,数据保存好了还不够,我们经常还需要对数据进行整理。

比如,监控系统收集了几十台 Linux 服务器的 CPU 使用率,我们希望按照使用率从高到低排列,快速找到最需要关注的服务器;又或者,我们需要按照磁盘使用率排序,优先处理空间不足的机器。

这些场景都离不开排序。

Python 提供了 sort() 和 sorted() 两种常用的排序方式。它们看起来很相似,但使用方法和适用场景并不完全相同。

这一篇,我们就把排序操作和前面学过的数据结构结合起来,看看不同类型的数据应该如何排序,以及实际开发中应该怎样选择合适的数据结构。

为什么需要排序?

先看一个简单的例子。

假设我们收集到了几台服务器的 CPU 使用率:

1
2
3
cpu_usage = [35, 82, 47, 96, 61]

print(cpu_usage)

运行结果:

1
[35, 82, 47, 96, 61]

这些数据记录了服务器的 CPU 使用率,但排列顺序比较随意。如果我们想快速找出 CPU 使用率最高的服务器,就需要逐个比较。

如果先对数据进行排序,情况就简单多了:

1
2
3
4
5
cpu_usage = [35, 82, 47, 96, 61]

sorted_usage = sorted(cpu_usage, reverse=True)

print(sorted_usage)

运行结果:

1
[96, 82, 61, 47, 35]

现在,CPU 使用率最高的数据就出现在列表最前面了。

当然,这里只有几个数字,手动查看也很容易。但如果监控系统收集了几百台甚至几千台服务器的数据,排序就能帮助我们更高效地整理信息。

在学习具体用法之前,先记住 Python 排序的两个核心工具:sort() 和 sorted()。

sort() 和 sorted() 有什么区别?

虽然这两个方法都可以排序,但它们的工作方式不同。

使用 sort() 原地排序

sort() 是列表对象的方法,只能直接用于 List。

它会修改原列表,而不是创建一个新的排序列表。

1
2
3
4
5
numbers = [35, 82, 47, 96, 61]

numbers.sort()

print(numbers)

运行结果:

1
[35, 47, 61, 82, 96]

默认情况下,sort() 按照升序排列,也就是从小到大。

如果想按照降序排列,可以设置 reverse=True:

1
2
3
4
5
numbers = [35, 82, 47, 96, 61]

numbers.sort(reverse=True)

print(numbers)

运行结果:

1
[96, 82, 61, 47, 35]

这里需要特别注意:sort() 会直接修改原列表,并且它的返回值是 None。

例如,下面这种写法就是错误的:

1
2
3
4
5
numbers = [3, 1, 2]

numbers = numbers.sort()

print(numbers)

运行结果:

1
None

为什么会这样?

因为 sort() 已经在原列表上完成了排序,但它并不返回排序后的列表。如果把它的返回值重新赋给 numbers,原本的列表引用就会被 None 替换。

所以,使用 sort() 时,直接调用即可:

1
numbers.sort()

使用 sorted() 返回新列表

与 sort() 不同,sorted() 是 Python 的内置函数,可以接收多种可迭代对象,例如 List、Tuple、Set、Dict 等。

它会返回一个新的列表,而不会直接修改原来的数据。

1
2
3
4
5
6
numbers = [35, 82, 47, 96, 61]

sorted_numbers = sorted(numbers)

print("原列表:", numbers)
print("排序结果:", sorted_numbers)

运行结果:

1
2
原列表: [35, 82, 47, 96, 61]
排序结果: [35, 47, 61, 82, 96]

可以看到,原列表的顺序保持不变,排序结果则保存在新列表中。

同样,我们可以使用 reverse=True 实现降序排序:

1
2
3
4
5
numbers = [35, 82, 47, 96, 61]

sorted_numbers = sorted(numbers, reverse=True)

print(sorted_numbers)

运行结果:

1
[96, 82, 61, 47, 35]

那么,什么时候使用哪一种?

如果只需要调整原列表的顺序,可以使用 sort();如果需要保留原始数据,同时得到排序结果,则使用 sorted()。

List 列表排序

List 是最常见的排序对象,因为它本身就是一种有序、可变的数据结构。

除了数字,我们还可以对字符串列表进行排序。

对字符串进行排序

例如,我们保存了几台服务器的名称:

1
2
3
4
5
servers = ["web-03", "web-01", "db-01", "web-02"]

servers.sort()

print(servers)

运行结果:

1
['db-01', 'web-01', 'web-02', 'web-03']

默认情况下,字符串会按照 Unicode 码点顺序进行比较。

对于这里的服务器名称,这样的排序方式通常比较直观。但如果字符串中包含大小写、中文或数字编号,就需要根据实际需求考虑排序规则。

使用 reverse() 反转列表

列表还提供了 reverse() 方法,用于直接反转当前列表中的元素顺序。

1
2
3
4
5
numbers = [1, 2, 3, 4, 5]

numbers.reverse()

print(numbers)

运行结果:

1
[5, 4, 3, 2, 1]

注意,reverse() 和 sort(reverse=True) 并不是一回事。

reverse() 只会反转当前顺序,不会比较元素大小;sort(reverse=True) 则会先按照排序规则排列,再以降序方式组织结果。

例如:

1
2
3
4
5
6
7
numbers = [3, 1, 5, 2, 4]

numbers.reverse()
print(numbers)

numbers.sort(reverse=True)
print(numbers)

运行结果:

1
2
[4, 2, 5, 1, 3]
[5, 4, 3, 2, 1]

这两个方法的用途不同,不要混淆。

Tuple 元组排序

前面我们学习过,Tuple 是不可变的数据结构。创建元组后,不能像列表一样直接修改其中的元素。

那么,如果需要对元组进行排序,应该怎么办?

答案是使用 sorted()。

1
2
3
4
5
6
numbers = (3, 1, 2)

sorted_numbers = sorted(numbers)

print(sorted_numbers)
print(numbers)

运行结果:

1
2
[1, 2, 3]
(3, 1, 2)

这里有一个细节:虽然输入的是 Tuple,但 sorted() 返回的仍然是 List。

如果希望最终结果依然是元组,可以再使用 tuple() 转换:

1
2
3
4
5
numbers = (3, 1, 2)

sorted_numbers = tuple(sorted(numbers))

print(sorted_numbers)

运行结果:

1
(1, 2, 3)

不过,如果没有必须保留元组类型的需求,直接使用 sorted() 的返回结果就可以了。

毕竟,排序操作本身并不会让元组变得可变,我们只是创建了一个新的排序结果。

Set 集合排序

Set 集合有一个重要特点:元素唯一,不保证按照插入顺序保存元素。

例如:

1
2
3
numbers = {5, 1, 3, 2, 4}

print(numbers)

集合的输出顺序不应该被当作固定顺序使用。

如果希望按照从小到大的顺序查看集合中的元素,可以使用 sorted():

1
2
3
4
5
numbers = {5, 1, 3, 2, 4}

sorted_numbers = sorted(numbers)

print(sorted_numbers)

运行结果:

1
[1, 2, 3, 4, 5]

需要注意,sorted() 返回的是列表,而不是集合。

这其实很合理:集合本身不负责维护排序后的顺序,而列表可以按照指定顺序保存元素。

如果只是临时查看排序结果,直接使用 sorted() 就足够了。

如果后续业务还需要集合的去重和集合运算能力,就可以继续保留原始 Set,而不必为了排序把它替换掉。

Dict 字典排序

字典与 List、Tuple、Set 有一个重要区别:它保存的是键值对。

在现代 Python 中,字典会保留键值对的插入顺序,但这并不意味着字典会自动按照键或值进行排序。

如果需要对字典中的数据排序,就要先明确:我们到底是想按照键排序,还是按照值排序?

按照键排序

例如,我们保存了不同服务器的 CPU 使用率:

1
2
3
4
5
6
7
8
9
cpu_usage = {
"web-03": 82,
"web-01": 35,
"db-01": 61
}

sorted_names = sorted(cpu_usage)

print(sorted_names)

运行结果:

1
['db-01', 'web-01', 'web-03']

直接对字典使用 sorted(),默认遍历并排序的是字典的键。

因此,这段代码得到的是一个按照键排序的列表,而不是一个新的字典。

如果希望得到按照键排序的字典,可以使用 sorted() 获取排序后的键值对,再通过 dict() 创建字典:

1
2
3
4
5
6
7
8
9
cpu_usage = {
"web-03": 82,
"web-01": 35,
"db-01": 61
}

sorted_cpu = dict(sorted(cpu_usage.items()))

print(sorted_cpu)

运行结果:

1
{'db-01': 61, 'web-01': 35, 'web-03': 82}

这个新字典会按照排序后的顺序插入键值对,因此在后续遍历时也会保持这个顺序。

按照值排序

如果我们更关心的是哪台服务器的 CPU 使用率最高,就应该按照值排序。

这时可以使用 items() 获取键值对,再通过 key 参数指定排序依据:

1
2
3
4
5
6
7
8
9
10
11
12
cpu_usage = {
"web-03": 82,
"web-01": 35,
"db-01": 61
}

sorted_cpu = sorted(
cpu_usage.items(),
key=lambda item: item[1]
)

print(sorted_cpu)

运行结果:

1
[('web-01', 35), ('db-01', 61), ('web-03', 82)]

这里的 item 是一个包含键和值的元组。

例如,("web-03", 82) 中,item[0] 表示服务器名称,item[1] 表示 CPU 使用率。

key=lambda item: item[1] 的意思是:按照每个键值对中的第二个元素,也就是 CPU 使用率进行排序。

如果想把 CPU 使用率最高的服务器排在最前面,可以加上 reverse=True:

1
2
3
4
5
6
7
sorted_cpu = sorted(
cpu_usage.items(),
key=lambda item: item[1],
reverse=True
)

print(sorted_cpu)

运行结果:

1
[('web-03', 82), ('db-01', 61), ('web-01', 35)]

这样,我们就能快速找出 CPU 使用率最高的服务器。

需要注意,sorted() 返回的是包含元组的列表。如果想将结果重新转换成字典,也可以使用 dict(sorted_cpu)。

实战:按照 CPU 使用率找出高负载服务器

前面我们分别学习了不同数据结构的排序方法,现在把它们组合起来,完成一个更贴近实际运维工作的例子。

假设我们通过监控系统获取了多台服务器的 CPU 使用率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
servers = {
"web-01": 35,
"web-02": 92,
"web-03": 68,
"db-01": 85,
"db-02": 41
}

sorted_servers = sorted(
servers.items(),
key=lambda item: item[1],
reverse=True
)

print("CPU 使用率从高到低:")

for name, usage in sorted_servers:
print(f"{name}: {usage}%")

运行结果:

1
2
3
4
5
6
CPU 使用率从高到低:
web-02: 92%
db-01: 85%
web-03: 68%
db-02: 41%
web-01: 35%

现在,CPU 使用率最高的服务器已经排在最前面。

如果我们只想找出 CPU 使用率超过 80% 的服务器,还可以在排序结果上继续筛选:

1
2
3
for name, usage in sorted_servers:
if usage > 80:
print(f"需要关注: {name}, CPU 使用率: {usage}%")

运行结果:

1
2
需要关注: web-02, CPU 使用率: 92%
需要关注: db-01, CPU 使用率: 85%

这个例子展示了字典、排序、循环和条件判断如何配合使用。

实际工作中,CPU 使用率通常由监控系统或采集程序实时获取。我们可以将采集到的数据组织成字典,再通过排序和筛选生成巡检报告。

当然,CPU 使用率高并不一定代表服务器发生故障,还需要结合业务负载、持续时间和其他监控指标进行判断。排序的作用,是帮助我们优先发现值得关注的对象。

key 参数还能做什么?

前面我们使用了 key=lambda item: item[1],指定按照字典值进行排序。

实际上,key 参数并不局限于数字,也可以用于指定字符串长度、时间字段或者其他排序规则。

例如,我们想按照服务器名称的长度排序:

1
2
3
4
5
servers = ["web-01", "database-01", "api-01", "cache-01"]

sorted_servers = sorted(servers, key=len)

print(sorted_servers)

运行结果:

1
['web-01', 'api-01', 'cache-01', 'database-01']

这里的 key=len 表示按照字符串长度进行排序。

如果两个服务器名称的长度相同,Python 的排序是稳定的,会保留它们在原始可迭代对象中的相对顺序。

这也意味着,我们可以根据业务需要定义自己的排序规则,而不必局限于数字大小或字符串本身的顺序。

排序操作速查

把前面的内容整理一下:

操作适用对象是否修改原数据返回结果
list.sort()List是None
sorted(data)多种可迭代对象否新的 List
list.reverse()List是None
sorted(data, reverse=True)多种可迭代对象否降序排列的新 List
sorted(dict.items(), key=...)Dict 的键值对否排序后的键值对列表

实际选择时,可以记住以下原则:

  • 需要直接修改列表顺序时,使用 sort()。
  • 需要保留原始数据时,使用 sorted()。
  • 只想反转现有列表顺序时,使用 reverse()。
  • 需要按照特定字段排序时,使用 key 参数。
  • 排序 Set、Tuple 或 Dict 时,要记住 sorted() 返回的是列表。

写在最后

这一篇,我们学习了 Python 的排序操作,掌握了 sort()、sorted() 和 reverse() 的区别,也了解了 List、Tuple、Set 和 Dict 分别应该如何排序。

回顾前面的内容,我们已经逐步认识了 Python 中常见的数据结构:

List 用来保存有序数据,Tuple 用来保存不可变序列,Set 用来处理不重复元素和集合运算,Dict 用来管理键值对应关系,而排序操作则帮助我们按照业务需要整理这些数据。

在 Linux 运维自动化中,这些知识经常会组合使用。比如,使用 Dict 保存服务器信息,再根据 CPU 或磁盘使用率进行排序,最后筛选出需要优先处理的服务器。

到这里,Python 常见数据结构的基础知识就有了一个比较完整的框架。