使用list.clear()与赋值空列表的性能差异及原因探究
列表清空操作的性能差异原因解析
两种清空列表的方式在底层实现上完全不同,这直接导致了它们在不同场景下的性能差异:
两种操作的本质区别
a = []:创建一个全新的空列表实例,原来的列表对象因为失去所有引用,会被Python的垃圾回收器处理。a.clear():在原有列表实例上清空内部元素,保留列表本身的内存结构(比如已经分配好的底层数组空间)。
小列表场景:clear()更快
对于元素数量少的小列表,clear()的操作极其轻量化——它只需要把列表的长度标记(内部的ob_size字段)设为0,不需要遍历元素,也不需要调整底层数组的内存。而a = []则需要创建一个新的空列表对象,虽然空列表的初始化开销很低,但相比直接修改现有对象的一个属性,多了对象创建的完整流程(比如初始化列表结构体、分配默认的小内存块),所以会慢约7%,和测试结果完全匹配。
对应的测试代码:
$ python --version Python 3.11.0 $ python -m timeit 'a = [1, 2, 3, 4]; a= []' 5000000 loops, best of 5: 61.5 nsec per loop $ python -m timeit 'a = [1, 2, 3, 4]; a.clear()' 5000000 loops, best of 5: 57.4 nsec per loop
大列表场景:a = []更快
当列表包含大量元素时,clear()必须遍历列表中的每一个元素,将它们的引用计数减1,标记为可回收;同时会保留原列表的底层数组空间(这个优化是为了后续添加元素时避免重新分配内存,但在当前测试场景下完全用不上)。而a = []只是创建新的空列表,原来的大列表对象的引用计数直接归零,垃圾回收器可以一次性处理整个对象,不需要逐个遍历元素修改引用计数。对于10000个元素的列表来说,遍历所有元素的开销远大于创建新空列表+回收旧对象的总开销,所以a = []的整体速度更快。
对应的测试代码:
$ python -m timeit 'a = list(range(10_000)); a = []' 2000 loops, best of 5: 134 usec per loop $ python -m timeit 'a = list(range(10_000)); a = []' 2000 loops, best of 5: 132 usec per loop $ python -m timeit 'a = list(range(10_000)); a = []' 2000 loops, best of 5: 134 usec per loop $ python -m timeit 'a = list(range(10_000)); a.clear()' 2000 loops, best of 5: 143 usec per loop $ python -m timeit 'a = list(range(10_000)); a.clear()' 2000 loops, best of 5: 139 usec per loop $ python -m timeit 'a = list(range(10_000)); a.clear()' 2000 loops, best of 5: 139 usec per loop
内容的提问来源于stack exchange,提问作者Martin Thoma
相关产品推荐
相关产品推荐

