sorted() 新建列表致内存翻倍,list.sort() 原地排序几乎零增量;不可变类型只能用 sorted();key 函数需避免耗时操作,宜预处理或用 itemgetter;大数据应选 heapq 或外部排序。

sorted() 和 list.sort() 的内存差异很真实
python 排序操作不是“免费的”,sorted() 会新建列表,list.sort() 是原地排序——这直接决定你程序吃不吃得消。尤其处理几十万行日志、上百万条记录时,差的不是几毫秒,是几百MB内存。
-
sorted()返回新列表,原列表不变,内存占用 ≈ 原数据 × 2(临时副本 + 结果) -
list.sort()不返回值(返回None),只改原列表,内存增量几乎为 0 - 如果后续不再需要原始顺序,硬用
sorted()就是主动给自己加压 - 注意:字符串、元组等不可变类型只能用
sorted(),因为没.sort()方法
key 参数写错会导致隐式复制和性能暴跌
很多人以为 key=Lambda x: x[1] 只是“取第二项”,但若 x 是大对象(比如含 json 字段的字典),每次调用 lambda 都可能触发深层拷贝或计算——特别是 key 函数里写了 json.loads()、re.search() 或访问数据库字段时。
- 避免在
key里做耗时操作;先预处理好排序键,存成新字段或缓存列表 - 用
operator.itemgetter('field')替代lambda x: x['field'],更快且不引发意外引用 - 如果 key 计算结果可复用(比如解析一次时间戳),提前算好并 zip 到数据中:
list(zip(parsed_keys, data)),再按第一列排序
小数据用内置排序,大数据考虑 heapq 或外部排序
Python 的 Timsort 在小到中等规模(
- 确认数据量:用
sys.getsizeof()粗略估算总内存(注意它不计嵌套对象,需递归估算) - 单次排序 >500MB?别硬扛,改用
heapq.merge()分块排序合并,或导出到 sqlite 用ORDER BY -
heapq.nsmallest(n, iterable)比先sorted()再切片快得多,尤其当n
自定义类排序时 __lt__ 实现不当会悄悄吃内存
给类加 __lt__ 支持排序很常见,但若里面调用了 self.to_dict() 或 json.dumps(self),每次比较都生成新对象,排序 O(n log n) 次调用 = O(n log n) 次内存分配。
立即学习“Python免费学习笔记(深入)”;
- 只在
__lt__里比核心字段,比如return self.priority - 避免在比较方法里做序列化、格式化、网络请求等副作用操作
- 如果必须依赖复杂逻辑,提前把排序键存在实例属性里(如
self._sort_key = compute_key(self)),然后直接比这个属性
排序本身不慢,慢的是你没意识到每个函数调用、每次对象创建、每一份隐式副本都在堆上留下痕迹。真正卡住的往往不是算法复杂度,而是某次 sorted([huge_dict_list], key=lambda d: d['config']['timeout']) —— 那个 ['config']['timeout'] 路径查找,底层反复构造中间 dict 视图,没人告诉你它不便宜。