max()需用key参数按属性取最大值,不可直接调用._max();空列表须设default,字段缺失用.get()兜底,复杂逻辑提为变量或函数,itemgetter适用于简单取值,自定义类应实现__lt__或用key而非__max__。

max() 函数本身不支持直接提取最大值的“某个属性”
很多人写 max(my_list)._max() 或 max(my_list).max(),结果报 AttributeError: 'int' object has no attribute '_max' —— 因为 max() 是内置函数,不是列表方法,更不存在 _max() 这种私有方法。
真正要从对象列表里按字段取最大值,得靠 key 参数。比如你有一堆字典或命名元组,想按 'score' 字段找最高分那条记录,max() 完全能干,但必须显式告诉它“比什么”。
-
max()默认只适用于可比较类型(如数字、字符串),对字典/对象直接调用会报TypeError: unorderable types -
key必须是函数,返回一个可比较的值;不能传字符串字段名(像 Pandas 那样) - 如果列表为空,
max()直接抛ValueError: max() arg is an empty sequence,生产环境务必加default=...
用 lambda 写 key 最常见,但别在循环里重复定义
比如找分数最高的学生:max(students, key=lambda x: x['score'])。这没问题,但如果你在 for 循环里反复写这个 lambda,Python 每次都会新建函数对象——不报错,但浪费内存和 CPU。
更稳的做法是把 key 提成变量或普通函数,尤其当逻辑稍复杂时(比如需要处理缺失字段、类型转换):
get_score = lambda s: s.get('score', 0)
best_student = max(students, key=get_score, default=None)
- 用
.get('score', 0)避免KeyError,比直接写x['score']更健壮 -
default=None让空列表返回None而非崩溃,后续可用if best_student:判断 - 别用
key=lambda x: int(x['score'])强转,万一字段是空字符串或 None,这里就崩了
用 operator.itemgetter 比 lambda 稍快,但仅限取字段
如果只是单纯取字典键或元组索引,operator.itemgetter 是比 lambda 更轻量的选择,底层用 C 实现,微小但可测的性能优势,且语义更清晰:
from operator import itemgetter
best = max(data_list, key=itemgetter('price')) # 字典
best = max(tuples, key=itemgetter(2)) # 元组第3个元素
-
itemgetter('name')等价于lambda x: x['name'],但不可处理缺失、转换、计算逻辑 - 遇到嵌套结构(如
x['meta']['created_at'])还是得回 lambda,itemgetter不支持链式访问 - PyPy 下差异不大,CPython 中大量数据时能省几个微秒,但别为此牺牲可读性
自定义类要用 __lt__ 或 key,别依赖 __max__
有人以为给类加个 __max__ 方法就能让 max() 自动识别,其实 Python 根本不调用它——max() 只认 key 或对象自身的比较协议(__lt__ 等)。
两种靠谱做法:
- 实现
__lt__:让实例天然可比,max()就能直接用,适合“这个类天然有个主排序维度”的场景 - 保持类干净,用
key=lambda obj: obj.priority:更灵活,不污染类定义,也避免意外影响其他排序逻辑 - 别在
__lt__里写复杂逻辑或 IO,max()内部会多次调用它,性能敏感时容易翻车
空列表、字段缺失、类型混杂——这些不是边缘情况,是线上最常触发 max() 报错的地方。写 key 时多想半秒怎么兜底,比事后查日志快得多。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











