← 返回题目列表

Python 中 list.sort 和 sorted 有什么区别?

高频 简单 第 1 / 21 题 更新于 2026/07/25
Pythonsortsorted排序
学习 AI 实战项目

简化版

list.sort() 是列表的原地排序方法,会修改原列表并返回 None;sorted() 是内置函数,接收任意可迭代对象,返回一个新的排序列表。二者都支持 key 和 reverse,Python 排序是稳定排序。

详细版

示例:

nums = [3, 1, 2]
result = nums.sort()
print(nums)    # [1, 2, 3]
print(result)  # None
nums = [3, 1, 2]
new_nums = sorted(nums)
print(nums)      # [3, 1, 2]
print(new_nums)  # [1, 2, 3]

区别:

对比项list.sort()sorted()
是否修改原对象是否
返回值None新列表
适用对象list任意可迭代对象
是否支持 key/reverse支持支持

按字段排序:

users = [{"name": "Tom", "age": 18}, {"name": "Jerry", "age": 16}]
users.sort(key=lambda user: user["age"])

稳定排序意味着:如果两个元素 key 相等,它们原来的相对顺序会保留。

完整版教学

一、list.sort() 是原地排序

list.sort() 修改原列表:

nums = [3, 1, 2]
nums.sort()
print(nums)  # [1, 2, 3]

它返回 None,不是排序后的列表:

nums = [3, 1, 2]
nums = nums.sort()
print(nums)  # None

这个设计是为了提醒你:这个方法是原地修改,不要把它当成创建新列表的函数。

原地排序的好处是少创建一个外层列表,适合你确定不再需要原顺序的场景。坏处也很明显:调用后原列表顺序被改变,其他引用这个列表的代码也会看到变化。比如多个变量指向同一个列表时,a.sort() 会让 b 看到排序后的结果。

a = [3, 1, 2]
b = a
a.sort()
print(b)  # [1, 2, 3]

二、sorted() 返回新列表

sorted() 不修改原可迭代对象,而是返回新列表:

nums = [3, 1, 2]
new_nums = sorted(nums)

print(nums)      # [3, 1, 2]
print(new_nums)  # [1, 2, 3]

它还能处理 tuple、set、dict keys、生成器等可迭代对象:

sorted((3, 1, 2))
sorted({"b", "a", "c"})
sorted({"b": 2, "a": 1})

返回值始终是 list。

这意味着 sorted() 适合保留原数据、对非 list 可迭代对象排序、或者函数式地生成排序结果。比如 sorted({"b": 2, "a": 1}) 排的是 dict 的 key,返回 ["a", "b"];如果想按 value 排,要显式使用 items() 和 key 函数。

对比项list.sort()sorted()
修改原对象是否
返回值None新 list
输入类型list任意可迭代对象
内存更省外层列表需要新列表

三、key 参数是排序的灵魂

key 接收一个函数,用来提取排序依据:

words = ["python", "go", "java"]
print(sorted(words, key=len))  # ['go', 'java', 'python']

对象列表排序:

users = [
    {"name": "Tom", "age": 18},
    {"name": "Jerry", "age": 16},
]

sorted_users = sorted(users, key=lambda u: u["age"])

多字段排序可以返回 tuple:

sorted_users = sorted(users, key=lambda u: (u["age"], u["name"]))

Python 会先比 age,相等时再比 name。

key 函数会对每个元素调用一次,Python 内部会缓存 key 结果用于排序,不是每比较一次都重新调用。这个设计比老式比较函数更高效,也更容易读。复杂对象排序时,优先写清楚 key,而不是把比较逻辑散落在循环里。

from operator import itemgetter

users = [{"name": "Tom", "age": 18}, {"name": "Jerry", "age": 16}]
print(sorted(users, key=itemgetter("age")))

四、reverse 控制整体降序

nums = [1, 3, 2]
print(sorted(nums, reverse=True))  # [3, 2, 1]

如果只想某个字段降序、另一个字段升序,可以在 key 里处理:

students = [
    {"name": "A", "score": 90, "age": 18},
    {"name": "B", "score": 90, "age": 17},
]

sorted_students = sorted(students, key=lambda s: (-s["score"], s["age"]))

这里分数降序,年龄升序。

要注意 reverse=True 是对整个排序结果反转,不是“只让某个字段降序”。多字段混合升降序时,可以像上面那样对数字字段取负,或者分多次利用稳定排序。对于字符串字段的降序,取负不适用,常用多次稳定排序或自定义 key 变换。

五、稳定排序有什么用

稳定排序表示:两个元素排序 key 相等时,它们原来的相对顺序不变。

这让你可以分多次排序:

students.sort(key=lambda s: s["age"])
students.sort(key=lambda s: s["score"], reverse=True)

因为排序稳定,第二次按分数排时,相同分数内部仍保持第一次年龄排序后的顺序。

Python 的排序算法是 Timsort,适合处理真实世界中常见的部分有序数据。面试不一定要展开算法细节,但可以知道它是稳定排序。

数字例子:先按年龄升序排,再按分数降序排;因为第二次排序稳定,相同分数的人仍保持年龄升序。这个技巧能让混合排序逻辑更清楚,特别是某些字段要升序、某些字段要降序时。

students = [
    {"name": "A", "score": 90, "age": 18},
    {"name": "B", "score": 90, "age": 17},
    {"name": "C", "score": 95, "age": 20},
]

students.sort(key=lambda s: s["age"])
students.sort(key=lambda s: s["score"], reverse=True)

记忆钩子:稳定排序让“先按次要字段排,再按主要字段排”成为可靠技巧。

六、常见边界:不可比较元素和 None

Python 3 不会随便比较不同类型对象。例如 [1, "2"] 排序会报错,因为 int 和 str 没有默认大小关系。包含 None 的数据也要明确排序规则,不能期待 Python 自动知道 None 应该排最前还是最后。

items = [3, None, 1]
print(sorted(items, key=lambda x: (x is None, x if x is not None else 0)))

上面 key 的第一项让非 None 排前面,None 排后面;第二项才是数值排序。实际业务里,缺失值、大小写、中文排序、自然排序都要明确规则。

七、常见误区与追问

  • 误区:sort() 返回排序后的列表。 它原地修改并返回 None,新列表用 sorted()。
  • 误区:sorted() 会保留输入类型。 它接收任意可迭代对象,但返回值始终是 list。
  • 误区:reverse=True 可以单独控制某个字段降序。 它反转整个结果,混合升降序要设计 key 或分多次稳定排序。
  • 追问:Python 排序稳定有什么用? key 相等时保留原相对顺序,可以分阶段排序。
  • 追问:key 函数什么时候执行? 通常每个元素提取一次 key,排序过程使用 key 结果比较。
  • 追问:不同类型混排为什么报错? Python 3 不定义任意类型之间的默认大小关系,需要显式 key。

八、加强记忆

把排序记成“是否改原列表”这条主线:list.sort() 改原列表、返回 None,适合不保留原顺序;sorted() 不改输入、返回新 list,适合任意可迭代对象。复杂排序用 key 提取规则,整体降序用 reverse,混合升降序和多级排序靠 tuple key 或稳定排序分步完成。