消除list.extend中不需要的副本

时间:2010-11-18 00:05:35

标签: python optimization

给出两个普通的python列表,newlistoldlist,带有整数index< len(oldlist),我想执行以下操作:

newlist.extend(oldlist[index:])

但没有创建中间列表oldlist[index:],或等效地

newlist.extend(oldlist[i] for i in xrange(index, len(oldlist)))

没有发电机的开销。这可能不使用C吗?

编辑:这个问题源自一些查看某些列表操作的c实现,特别是对于list.extend(),当解释器确定它可以猜测尾部的大小被添加到列表中时,它分配头部列表的完整大小,并在生成元素时复制元素;对于其他情况,它一次分配一些元素(大约八个,如果内存服务),并一次复制几个元素。

完成分配时的具体情况似乎是python列表,以及其他一些__len__的类型。据我所知,没有内置类型的“列表视图”可以满足这些要求。

4 个答案:

答案 0 :(得分:10)

不要猜测,衡量

create = """
oldlist = range(5000)
newlist = range(5000, 10000)
index = 500
"""
tests = [
    "newlist.extend(oldlist[index:])",
    "newlist.extend(oldlist[i] for i in xrange(index, len(oldlist)))",
    "newlist.extend(islice(oldlist, index, None))",
    """\
while index < len(oldlist):
   newlist.append(oldlist[index])
   index+=1""",
]

import timeit
for test in tests:
    t = timeit.Timer(create + test, setup='from itertools import islice')
    print test, min(t.repeat(number=100000))

newlist.extend(oldlist[index:]) 17.2596559525
newlist.extend(oldlist[i] for i in xrange(index, len(oldlist))) 53.5918159485
newlist.extend(islice(oldlist, index, None)) 19.6523411274
while index < len(oldlist):
   newlist.append(oldlist[index])
   index+=1 123.556715012

答案 1 :(得分:0)

显而易见的解决方案是:

while index < len(oldlist):
    newlist.append(oldlist[index])
    index += 1

但要对过早优化保持警惕,我从未遇到过这样一种情况,即这种解决方案中可读性的损失是值得的。当然,对所有选项进行基准测试,以确保您认为的解决方案更快,实际上是。

答案 2 :(得分:0)

appendnew = newlist.append
try:
    while 1:
        appendnew(oldlist[index])
        index += 1
except IndexError:
    pass

或稍微不那么令人难以置信:

appendnew = newlist.append
for i in xrange(index, len(oldlist)):
    appendnew(oldlist[i])

答案 3 :(得分:0)

有关更好基准测试的一些线索

测量开销并将其减去。

将代码放在函数或方法中(模拟现实;有助于确保将变量作为全局变量不会产生令人讨厌的影响)。

from itertools import islice
def f0(newlist, oldlist, index):
    pass
def f1(newlist, oldlist, index):
    newlist.extend(oldlist[index:])
def f2(newlist, oldlist, index):
    newlist.extend(oldlist[i] for i in xrange(index, len(oldlist)))
def f3(newlist, oldlist, index):
    newlist.extend(islice(oldlist, index, None))
def f4(newlist, oldlist, index):
    while index < len(oldlist):
        newlist.append(oldlist[index])
        index += 1


>python -mtimeit -s"old=range(1000);new=range(5000,10000);ix=500;import xtnd"; "xtnd.f4(new,old,ix)"

如果被基准测试的代码有一个变量N(在这种情况下是N = len(旧列表) - 索引),则基准测试具有多个N值。如果你期望O(N)行为,O(1)结果应该是是一个调查的原因。

同时比较具有合理预期的候选人的结果 - 应调查野生变异;它们可能是由实验错误引起的。