Python 重新填充而不是替换列表是否是提高速度的好策略,为什么?

Python 重新填充而不是替换列表是否是提高速度的好策略,为什么?,python,list,Python,List,假设我有一个对象列表。我需要反复更新它,使其成为一个过滤版本。我应该在什么时候通过重新填充现有列表而不是创建新列表来完成此任务?也就是说,在此设置中,在什么情况下对象重用比新对象创建更有效?一个简单的实验表明“永远不会”,这让我很惊讶 以说明,考虑以下的速度(Python 3.8,Win 10)。这很容易解释吗 import timeit #assign ordinary list comprehension (2 seconds) print(timeit.timeit(stmt="

假设我有一个对象列表。我需要反复更新它,使其成为一个过滤版本。我应该在什么时候通过重新填充现有列表而不是创建新列表来完成此任务?也就是说,在此设置中,在什么情况下对象重用比新对象创建更有效?一个简单的实验表明“永远不会”,这让我很惊讶

以说明,考虑以下的速度(Python 3.8,Win 10)。这很容易解释吗

import timeit

#assign ordinary list comprehension (2 seconds)
print(timeit.timeit(stmt="lst=[x for x in lst if x>5000];",setup="lst=list(range(10000));",number=10000))
#assign with `list` instead of brackets (3 seconds)
print(timeit.timeit(stmt="lst=list(x for x in lst if x>5000);",setup="lst=list(range(10000));",number=10000))
#reuse list, with generator (3.2 seconds)
print(timeit.timeit(stmt="lst[:]=(x for x in lst if x>5000);",setup="lst=list(range(10000));",number=10000))
如果可以合理地认为这是这个问题的一部分,我也想知道为什么过滤器总是慢30%以上

#assign from spread filter (4.2 seconds)
print(timeit.timeit(stmt="lst=[*filter(lambda x: x>5000, lst)];",setup="lst=list(range(10000));",number=10000))
#assign converted generator (4.4 seconds)
print(timeit.timeit(stmt="lst=list(filter(lambda x: x>5000, lst));",setup="lst=list(range(10000));",number=10000))
#reuse list, fill from filter (4.6 seconds)
print(timeit.timeit(stmt="lst[:]=filter(lambda x: x>5000, lst);",setup="lst=list(range(10000));",number=10000))

我想说,与其说是填写清单,不如说是创建相关的项目。列表操作非常快速和高效,我决不会认为这些操作有问题,除非有特定的边缘情况提示


此外,python是一种垃圾收集语言,这意味着在数组(隐式地)被取消引用之后,它最终将被清除。只要你有足够的内存,这就有效地分散了删除内容的负担。

过滤器的速度较慢,部分原因是你在每次迭代时都调用函数,函数调用开销并不是很小。注意,在
列表[:]=
表单中,我很确定在后台调用了
列表()
,这就解释了为什么它如此类似于
lst=list(generator)
无论如何,对于
list
对象,我的直觉告诉我,几乎没有比调整现有对象的大小更有效的了。基本上,底层缓冲区几乎肯定无论如何都必须重新分配,因此大的工作几乎是一样的。@juanpa.arrivillaga在这种情况下,“调整大小”总是一个缩小的过程。这还会导致重新分配吗?(我们怎么知道?)@ggorlen评测显示我在这方面花费了惊人的时间。我曾经认为重用列表是最好的(因为它避免了对象创建,并且永远不需要更长的列表)。我不确定这里的“推测”是什么。。。