Aug*_*sta 6 python optimization list slice micro-optimization
假设我有一个 ,list TruncList其元素数量大于n。如果我想n从该列表的末尾删除元素,将列表重新定义为保留所需元素的自身切片(如 by TruncList = TruncList[:-n])或从列表中删除不需要的元素的切片(del TruncList[-n:]如 by )更快吗?
如果我删除第一个 n元素,答案会改变吗TruncList,就像TruncList = TruncList[n:]vs一样del TruncList[:n]?
除了速度之外,这些方法中的一种是否比另一种更Pythonic?
我想重新定义方法可能会更慢,因为它会迭代TruncList然后重新分配它,同时del截断列表,但我不确定是否是这种情况。
我还认为del这是更好的路线,因为这似乎是该功能的自然使用。
这完全取决于您删除了多少元素。
在 CPython 中,该list类型使用动态过度分配策略来避免过于频繁地调整底层 C 数组的大小。有一个array用来容纳元件的支架,并且它始终保持稍大一些。
如果足够小,则删除(使用del TruncList[-n:])实际上可能是免费的操作。n事实上,在调整大小之前,您可以安全地删除最多一半的过度分配数组大小。调整大小需要将所有现有引用复制到新数组。
使用切片总是会创建新的列表对象,需要分配内存并复制所涉及的元素。这比重新分配数据的工作量稍微多一些。
因此,在不测量时间性能(使用timeit)的情况下,我希望该del选项比切片更快;在(小于长度的一半)的情况下,n < len(TruncList) // 2在许多情况下,您甚至不需要调整大小,即使您这样做了,需要做的工作也会稍微少一些,因为只需重新创建内部数组。
当您从前面删除项目时,您始终必须重新创建内部数组。那么差异不会很明显,但创建切片仍然会导致分配一个全新的对象。
timeit所以我自己使用这些示例进行了测试:
## Make a list of 500 elements and then remove the first 80...
def slice_front():
"Make the list equal to all but the first eighty elements."
trunc = 80
TruncList = range(500)
TruncList = TruncList[trunc:]
def del_front():
"Use del to remove the first eighty elements."
trunc = 80
TruncList = range(500)
del TruncList[:trunc]
## Make a list of 500 elements and then remove the last 80...
def slice_end():
"Make the list equal to all but the last eighty elements."
trunc = 80
TruncList = range(500)
TruncList = TruncList[:-trunc]
def del_end():
"Delete the last eighty elements from the list using del."
trunc = 80
TruncList = range(500)
del TruncList[-trunc:]
Run Code Online (Sandbox Code Playgroud)
...并得到这些结果:
>>> timeit.timeit(slice_front, number = 66666)
1.3381525804258112
>>> timeit.timeit(del_front, number = 66666)
1.0384902281466895
>>> timeit.timeit(slice_end, number = 66666)
1.3457694381917094
>>> timeit.timeit(del_end, number = 66666)
1.026411701603827
Run Code Online (Sandbox Code Playgroud)
看起来速度del更快,而且差距很大。
编辑
如果我运行相同的示例,但使用的trunc = 2是,结果如下:
>>> timeit.timeit(slice_front, number = 66666)
1.3947686585537422
>>> timeit.timeit(del_front, number = 66666)
1.0224893312699308
>>> timeit.timeit(slice_end, number = 66666)
1.4089230444569498
>>> timeit.timeit(del_end, number = 66666)
1.042288032264116
Run Code Online (Sandbox Code Playgroud)
del还是比较快的。
这是一个几乎所有列表元素都被删除的测试:trunc = 80并且TruncList = range(81)......
>>> timeit.timeit(slice_front, number = 66666)
0.25171681555993247
>>> timeit.timeit(del_front, number = 66666)
0.2696609454136185
>>> timeit.timeit(slice_end, number = 66666)
0.2635454769274057
>>> timeit.timeit(del_end, number = 66666)
0.294670910710936
Run Code Online (Sandbox Code Playgroud)
在这种情况下,del比重新定义方法要慢一些。
| 归档时间: |
|
| 查看次数: |
3366 次 |
| 最近记录: |