Python中list添加元素操作效率问题探讨

IMG 明天电脑研究一下🤔


Python中list添加元素操作效率问题探讨
15 回复

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

回到顶部