跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何在Python中根据对象的多个属性进行排序_使用operator.itemgetter函数

operator.itemgetter比lambda更适合多字段排序,因其是C实现、性能更优,支持字典/序列的多键取值,返回可复用函数;但不支持属性访问、缺失键默认值或混合升降序,需配合lambda等补充。 为什么
operator.itemgetter
比
lambda
更适合多字段排序 因为
itemgetter
是 C 实现的,调用开销更低,尤其在大数据量排序时性能更稳定;它还天然支持嵌套取值(如
itemgetter('a', 'b.c')
不行,但
itemgetter('a', ('b', 'c'))
也不行——得注意它只对字典/映射类对象按 key 取值,不递归解析点号路径);更重要的是,它返回的是可哈希、可复用的函数对象,适合多次传入
sorted()
或
list.sort()
。 常见错误是误以为
itemgetter
能处理对象属性(比如
obj.name
),但它只认字典键或序列索引。对自定义对象,得用
attrgetter
,不是
itemgetter
。 对字典列表:直接用
itemgetter('name', 'age')
对元组/列表:用
itemgetter(0, 2)
(按第 1 和第 3 个元素) 混合升序降序?
itemgetter
本身不支持,得靠
reverse
或包装成
key
函数 怎么用
itemgetter
实现多字段升序+降序组合
itemgetter
本身只返回元组,Python 元组默认按位置逐项比较,天然支持“主字段升序、次字段降序”这类需求——只要把要降序的字段取负值(仅限数值)或用
reversed
预处理(不推荐),更通用的做法是分两步:先按次要字段降序排,再主字段升序稳定排序(利用
sorted
的稳定性)。 但最简方案仍是构造复合 key:对字符串字段无法取负,所以得用
lambda
辅助。不过多数场景下,先统一升序,再用
reverse=True
控制整体顺序就够了。 立即学习 “ Python免费学习笔记(深入) ”; Python 3.14.3 微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。 下载 全升序:
sorted(data, key=itemgetter('score', 'name'))
先按
'score'
降序,再按
'name'
升序:
sorted(data, key=itemgetter('score'), reverse=True); then sorted(..., key=itemgetter('name'))
——不行,会破坏前序结果;正确做法是:
sorted(data, key=lambda x: (-x['score'], x['name']))
,此时已不适合纯
itemgetter
若所有字段都支持取负(如全是数字),可用
key=lambda x: (-x['a'], x['b'], -x['c'])
,但这就脱离了
itemgetter
的初衷
itemgetter
在字典和 namedtuple 中的行为差异 对普通字典,
itemgetter('x', 'y')
返回一个二元元组,如
('val_x', 'val_y')
;对
namedtuple
,它同样工作,因为
namedtuple
支持通过 key 名访问(底层是映射协议)。但对普通 class 实例,即使有
.x
和
.y
属性,
itemgetter
会报
TypeError: unhashable type: 'dict'
或
KeyError
,因为它尝试用
__getitem__
而非
getattr
。 字典列表 ✅:
[{'a': 1, 'b': 2}, {'a': 1, 'b': 1}] → itemgetter('a','b')
namedtuple
✅:
Point = namedtuple('Point', ['x', 'y']); p = Point(1,2); itemgetter('x','y')(p)
返回
(1, 2)
dataclass 或普通 class ❌:必须换
operator.attrgetter('x', 'y')
排序空值或缺失键时怎么避免
KeyError
itemgetter
遇到缺失 key 直接抛
KeyError
,不提供默认值。想安全取值,不能靠它内置机制,得自己包装一层。 典型做法是用
lambda
+
dict.get
,或者预处理数据补默认值。没有“带默认的 itemgetter”,别被网上某些误导代码骗了。 错误写法:
itemgetter('price', 'category')
在某条数据缺
'price'
时崩溃 安全替代:
lambda d: (d.get('price', 0), d.get('category', ''))
如果坚持用函数式风格,可写个简易 wrapper:
safe_get = lambda *keys: lambda d: tuple(d.get(k, None) for k in keys)
,然后
sorted(data, key=safe_get('a', 'b'))
真正容易被忽略的是:排序稳定性只在同一次
sorted
调用内有效;跨多次调用重排序,顺序可能变。还有,
itemgetter
返回的 key 函数不校验数据类型,比如拿字符串和
None
比较会抛
TypeError
,这得靠上游数据清洗或 key 包装兜底。

相关文章