Python中list添加元素操作效率问题探讨
明天电脑研究一下🤔
Python中list添加元素操作效率问题探讨
iadd 是原地操作
在Python里,往list里加元素,最常用的就append()、insert()和extend()这几个方法,还有+和+=操作符。它们的效率差别挺大的,选错了在大数据量时性能会差很多。
核心结论:append()是O(1)常数时间复杂度,最快;insert(0, item)在开头插入是O(n)线性时间,最慢,要尽量避免。
下面用代码和耗时对比来直观感受一下:
import timeit
# 1. 测试 append() 在末尾添加
def test_append():
lst = []
for i in range(10000):
lst.append(i)
return lst
# 2. 测试 insert(0, item) 在开头添加
def test_insert_front():
lst = []
for i in range(10000):
lst.insert(0, i) # 每次都在索引0处插入
return lst
# 3. 测试用 + 连接列表
def test_plus_operator():
lst = []
for i in range(10000):
lst = lst + [i] # 创建新列表,效率低
return lst
# 4. 测试用 += 或 extend()
def test_extend():
lst = []
for i in range(10000):
lst += [i] # 相当于extend,原地修改
return lst
# 运行时间测试
print("append() 耗时:", timeit.timeit(test_append, number=1000))
print("insert(0, ...) 耗时:", timeit.timeit(test_insert_front, number=1000))
print("+ 操作符耗时:", timeit.timeit(test_plus_operator, number=1000))
print("+= 操作符耗时:", timeit.timeit(test_extend, number=1000))
运行结果大致是:
append()和+=(extend())非常快,耗时最短。insert(0, ...)慢一个数量级,因为它每次都要移动所有已有元素。+操作符最慢,因为它每次循环都创建新列表,复杂度是O(n²)。
原理很简单:Python的list是动态数组,append()在数组末尾预留了空间,不够时才扩容,平均是O(1)。而insert(0, x)在开头插入,需要把后面所有元素都往后挪一位,是O(n)操作。+生成新列表,内存分配和数据复制开销大。
所以,日常就用append()来逐个加元素,用extend()或+=来合并另一个列表。除非特殊情况,否则别用insert(0, ...)和循环+。
总结:无脑用append()和extend()就对了。
“+=” is a shorthand of “ extend ”
m1 应该比 m2 快
+=。。。
我这边也是 m2 比 m1 要快。
>>> def m1(): x=[]; x.append(1)
>>> def m2(): x=[]; x+=[1]
>>> import dis
>>> dis.dis(m1)
1 0 BUILD_LIST 0
2 STORE_FAST 0 (x)
4 LOAD_FAST 0 (x)
6 LOAD_ATTR 0 (append)
8 LOAD_CONST 1 (1)
10 CALL_FUNCTION 1
12 POP_TOP
14 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>> dis.dis(m2)
1 0 BUILD_LIST 0
2 STORE_FAST 0 (x)
4 LOAD_FAST 0 (x)
6 LOAD_CONST 1 (1)
8 BUILD_LIST 1
10 INPLACE_ADD
12 STORE_FAST 0 (x)
14 LOAD_CONST 0 (None)
16 RETURN_VALUE
如何回复截图?我这执行结果是正常的。
借用宝地测试下发图:
代码:
执行结果:
个人猜测,可能是由于第一种和第二张速度差不多,执行次数少的时候收到一些随机性影响导致数据不同。
原来 append 最慢 我都这么➕
还可以考虑列表推导和.extend 这两个情况都测下
另外列表相加那个 最好看看内存
X86
%timeit m1()
1000 loops, best of 3: 908 µs per loop
%timeit m2()
1000 loops, best of 3: 1.93 ms per loop
算上空间占用的话,区别会很大,这两种方法都不算是最优的方法。
list 默认会预留一点空间用于扩容。append 的时候如果预留空间不够,就会重新申请内存去存储。相对于 list 的长度,如果 append 了少量的元素性能会很好。
列表生成器会直接预留足够的空间,再去填充元素。
实际应用中,这种场景直接用列表生成式是没错的。
试了好多次,m1 都不如 m2

