Python串联与列表上的追加速度

Posted

技术标签:

【中文标题】Python串联与列表上的追加速度【英文标题】:Python concatenation vs append speed on lists 【发布时间】:2014-10-02 17:28:34 【问题描述】:

从interactivepython.org获取这个sn-p:

def test1():  # concat
    l = []
    for i in range(1000):
        l = l + [i]

def test2():  # append
    l = []
    for i in range(1000):
        l.append(i)

concat  6.54352807999 milliseconds
append  0.306292057037 milliseconds

底部块是运行时间。

它说连接是 O(k),其中 k 是“被连接的列表的长度”。我不确定这是否意味着您要添加到的列表(原始),或者您将要添加的列表。但是在这两个循环中,您似乎每次迭代只执行 1 步。那么为什么追加这么快呢?

【问题讨论】:

【参考方案1】:

如果您将 test1 更改为:

def test1():  # concat
    l = []
    for i in range(1000):
        l += [i] 

时间会更近,而您实际上正在做append 不会每次都创建新列表的事情。

In [26]: %timeit test1()
10000 loops, best of 3: 169 µs per loop

In [27]: %timeit test2()
10000 loops, best of 3: 115 µs per loop

如果您将print id 放入您的代码中,您将在test1 中看到您每次都在创建一个新对象,但在test2 中它始终是同一个列表:

In [41]: test1()
139758194625352
139758206001808
139758205966960
139758194625352
139758206001808
139758205966960
139758194625352
139758206001808
139758205966960
139758194625352
Out[41]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [42]: test2()
139758206002600
139758206002600
139758206002600
139758206002600
139758206002600
139758206002600
139758206002600
139758206002600
139758206002600
139758206002600
Out[42]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

【讨论】:

注意+= [1]更像是扩展;在这种情况下,它使用listobj.extend([1])【参考方案2】:

因为连接必须在每次迭代时构建一个列表对象:

每次创建一个新列表比在现有列表中添加一个项目要昂贵得多。

在后台,.append() 将填充 C 数组中的预分配索引,并且列表对象只需要定期增长该数组。另一方面,构建一个新的列表对象每次都必须分配一个 C 数组。

【讨论】:

我很困惑,我在 Haskell 等函数式编程语言中学到了“追加”确实每次都会构建一个新的列表对象,那么这个含义是 Python 特有的吗? @GabbyQuattrone 是函数式语言特有的行为,其中类型永远不可变。可变性并非特定于 Python;许多其他语言的行为都是一样的。 如果这意味着将一项添加到现有列表中,那么他们为什么不将其称为 LISP 中的构造的缺点? @GabbyQuattrone:我不知道,你得问函数式编程专家这个问题。 @knowledge_is_power 因为 Haskell 和 Lisp 的命名约定与 Python 没有太大的关系,Python 是一个独立的编程语言谱系。在 Haskell 中,什么都不会发生变异

以上是关于Python串联与列表上的追加速度的主要内容,如果未能解决你的问题,请参考以下文章

vue怎么设置照片速度

追加和清空大型列表时的性能

python向nas上写入数据很慢

vue如何调速度

python 列表生成式和生成器的速度性能比较

Python heapq 与预排序列表的排序速度