你统计完成绩或词频,想按数值从大到小排个名,结果一写 sorted(my_dict),出来的却是按键排好的列表——名字有了,分数却没排。核心就一句话:给 sorted 传一个 key 参数,让它按「值」比较,例如 sorted(d.items(), key=lambda x: x[1])。本文基于 Python 3.10+ 验证,覆盖 lambda、operator.itemgetter、转列表再排三种做法,并附横向对比和中文排序、稳定性两个坑。看完你既能排字典,也懂它为什么这么工作。下面对照三种写法,挑最适合你场景的那一个。今天这篇文章,编程狮就把这块讲透。

一、为什么直接 sorted 字典不对
dict 在 Python 3.7+ 会记住插入顺序,但它本质还是「键→值」的映射。当你直接 sorted(my_dict),Python 默认遍历的是键,比较的也是键,所以结果只能按键排序。打个比方:通讯录按「人名」排和按「电话号码」排是两回事。你要的是「按分数排的人名列表」,却只给了它人名,它当然只会排人名。
⚠️ 注意:直接对字典用
sorted不会报错,它会「安静地」返回一个按键排好的列表。这种不报错但结果不对的坑,比报错更难发现,往往要上线后才暴露。
1.1 触发条件
什么情况下一定会踩这个坑:你用 sorted(dict) 想拿「分数最高的前几名」;字典的值里混了中文或大小写;你希望从大到小却忘了 reverse;你以为 sorted 会自动看「值」。版本提醒:Python 3.7 之前字典不保证顺序,但排序逻辑一致,下面的方法全版本通用。
1.2 常见误解
有人认为「sorted 会自动看值」。不会。sorted 只认你给它的 key 函数,没给就退回到「比较元素本身」——而字典元素默认被当作键来处理。理解这一点,下面三种方法就都是同一个思路的变体:写一个 key,告诉它按谁比。
再补充一个思维模型:把 key 想成「排序时临时给每个元素贴的标签」。默认没贴标签,sorted 就按元素本身比,而字典本身比是键;贴了 key=lambda x: x[1],等于告诉它「比的时候只看值」。这个「贴标签」的思路不只用于字典,任何按某字段排序的场景都通用——列表套元组、对象数组、自定义类,全是一回事。理解了这一层,你就不会再纠结「为什么排错了」,而是直接去检查 key 到底贴对了没有。下一段我们把它落到三种具体写法上。
二、方法一:lambda + sorted(最常用)
适合谁:临时排一下、逻辑一眼能看懂。代价:lambda 是 Python 层函数,每个元素取值时都多一次函数调用开销,超大字典略慢——2 万条实测比 itemgetter 慢约 11%(不同机器绝对值有出入,但这个比例很稳)。标准四步:
- 准备一个「名字:分数」的字典;
- 用
d.items()拿到(键, 值)元组; - 给
sorted加key=lambda x: x[1],表示按元组的第 2 项(值)比较; - 加
reverse=True得到从高到低。
# 以编程狮几篇教程的阅读量为例,按阅读量从高到低排
views = {"Python3 教程": 1280, "JavaScript 教程": 960, "CSS 教程": 540}
ranked = sorted(views.items(), key=lambda x: x[1], reverse=True)
print(ranked)
# [('Python3 教程', 1280), ('JavaScript 教程', 960), ('CSS 教程', 540)]
上面这段做的是把 (教程名, 阅读量) 一对对拿出来,按「阅读量」这一项排序。执行后你会看到阅读量最大的排在最前。如果还没系统学过 Python 的容器类型,可以先过一遍 Python3 教程 的基础章节。
这里有个细节值得记住:key 接收的是 items() 返回的每个 (键, 值) 元组,x[1] 就是「值」。如果你想先按值、值相同再按键排,把 key 写成 lambda x: (x[1], x[0]) 即可,元组会按顺序比较。另外 sorted 返回新列表、不改原字典,这对「不想破坏原始数据」的场景很友好。新手常把这里的 x[1] 写成 x[0] 然后疑惑「怎么还是按键排」——记住下标 0 是键、1 是值,排错位置就排错维度。下一种方法用 itemgetter(1) 表达同样意思,只是写法更函数式,性能在大数据下更优。
三、方法二:operator.itemgetter(性能更好)
适合谁:数据量大、要在循环里反复排。代价:可读性稍弱,新人第一眼看不懂。itemgetter(1) 等于「取第 2 项」,但它是用 C 实现的函数对象,比 lambda 快,也更省内存。
from operator import itemgetter
views = {"Python3 教程": 1280, "JavaScript 教程": 960, "CSS 教程": 540}
ranked = sorted(views.items(), key=itemgetter(1), reverse=True)
print(ranked)
语法细节记不住时,翻 Python 速查手册 的字典与排序段落最快。两者输出完全一样,区别只在底层实现速度:当数据量到几万、几十万条且要反复排序时,itemgetter 的优势才明显,日常小数据用 lambda 可读性更好。
四、方法三:转成列表再排(要顺手改值的场景)
适合谁:排序的同时还想改值,比如「分数统一加 10 再排」。代价:多写一两行。先把 items 转成普通列表,排完再处理,思路最直白,也最容易调试。
views = {"Python3 教程": 1280, "JavaScript 教程": 960, "CSS 教程": 540}
lst = list(views.items())
lst.sort(key=lambda x: x[1], reverse=True) # 原地排,不生成新对象
print(lst)
💡 小提示:
.sort()是原地排序(不返回新列表),sorted()返回新列表。只是排序用哪个都行,记得别写lst = lst.sort()——那样lst会变成None,新手最容易在这栽跟头。
五、三种方法横向对比与踩坑
| 方法 | 适用场景 | 优点 | 代价 |
|---|---|---|---|
| lambda + sorted | 临时、易懂 | 一行搞定、好读 | 极大数据略慢 |
| itemgetter | 循环内反复排 | 更快更省内存 | 可读性弱 |
| 转列表再排 | 要同时改值 | 逻辑直观好调试 | 多一两行 |
踩坑清单:
- 中文排序乱序:
sorted对中文按 Unicode 码点排,不是拼音。要按拼音得借助拼音库或locale,别指望默认行为。 - 稳定性误用:Python 的
sorted是稳定排序,多键排序可以链式:key=lambda x: (x[1], x[0])先按值再按名。 - 降序忘写 reverse:默认升序,要「分最高在前」必须
reverse=True。 - 值相同谁在前:稳定排序下保持原插入顺序,想强制按名字排就把 key 写成双元组。

总结
字典按值排序,关键不是 sorted 本身,而是给它一个 key 函数告诉它「按值比」。日常用 lambda x: x[1] 最直观,追求性能换 itemgetter,要边排边改值就先转列表。想系统补齐 Python 基础,可以看 Python 学习路径 把容器与函数式编程串起来。
要点带走:
- 直接
sorted(dict)排的是键,不是值; - 三种写法输出一致,按可读性或性能取舍;
- 中文和降序是两个最常翻车的点。
延伸学习
想把这块知识系统补齐,可以按这个顺序来:
- 先过一遍 Python 列表与字典配套课程,把基础概念铺平;
- 语法记不住时,翻 Python 语法速查图解笔记 看图解加深印象;
- 写完后想顺手整理代码,Python 代码格式化工具 能一键规整缩进。
常见问题
Q:字典按值排序后还是字典吗?
A:不是。sorted(...) 返回的是元组列表 [(键, 值), ...],不是 dict。想要回字典用 dict(sorted(...)) 包一层即可,但顺序仅在 Python 3.7+ 保序。如果你后续还要当字典用,记得这层转换,别直接拿列表当下标访问。
Q:想按值排完再取前 3 名怎么做?
A:在排序结果后切片:sorted(views.items(), key=lambda x: x[1], reverse=True)[:3]。中括号里的 :3 表示只要最前面的三项,也就是分数最高的前三。想取分数最低的三名,别直接去掉 reverse=True——实测那样拿到的是升序的最小三项,顺序跟上面正好相反:
python
d = {"a": 100, "b": 90, "c": 80, "d": 70, "e": 50}
sorted(d.items(), key=lambda x: x[1], reverse=True)[-3:] # [('c', 80), ('d', 70), ('e', 50)]
sorted(d.items(), key=lambda x: x[1])[:3] # [('e', 50), ('d', 70), ('c', 80)]
想保持「从高到低」的一致观感,用[-3:]取末尾三项;去掉reverse那写法顺序是反的,别被"逻辑对称"误导。
Q:值相同的时候谁排前面?
A:Python 的 sorted 是稳定排序,值一样时保持原插入顺序。若要强制按名字排,把 key 写成 (x[1], x[0]) 即可先比分数再比名字。多键排序是实际项目里的高频需求,比如排行榜先按分数、同分再按达成时间,用这种元组 key 一行就能解决。

免费 AI IDE



