发布于 4个月前

Python对比List Comprehension(列表推导式)和列表的append函数的效率

测试1:是否List Comprehension(列表推导式)就比list的append快:

def ():
    """Stupid test function"""
    L = []
    for i in range(100):
        L.append(i*2)
    return L
def test2():
    return [i * 2 for i in range(100)]
if __name__ == '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test"))
    print('------')
    print(timeit.timeit("test2()", setup="from __main__ import test2"))

结果如下:

16.2206947803
------
12.4496650696

看来List Comprehension确实比在一个列表上不停append要快。

测试2:使用dis查看函数的字节码:

import dis
def list_c(nums):
    return [i*2 for i in nums]
print 'return [i*2 for i in nums]'
dis.dis(list_c)
print '--------------'
print '--------------'
print '--------------'
def append_list(nums):
    alist = []
    for i in nums:
        alist.append(i*2)
    return alist
dis.dis(append_list)

结果如下:

return [i*2 for i in nums]
  5           0 BUILD_LIST               0
              3 LOAD_FAST                0 (nums)
              6 GET_ITER            
        >>    7 FOR_ITER                16 (to 26)
             10 STORE_FAST               1 (i)
             13 LOAD_FAST                1 (i)
             16 LOAD_CONST               1 (2)
             19 BINARY_MULTIPLY     
             20 LIST_APPEND              2
             23 JUMP_ABSOLUTE            7
        >>   26 RETURN_VALUE        
--------------
--------------
--------------
 17           0 BUILD_LIST               0
              3 STORE_FAST               1 (alist)
 18           6 SETUP_LOOP              31 (to 40)
              9 LOAD_FAST                0 (nums)
             12 GET_ITER            
        >>   13 FOR_ITER                23 (to 39)
             16 STORE_FAST               2 (i)
 19          19 LOAD_FAST                1 (alist)
             22 LOAD_ATTR                0 (append)
             25 LOAD_FAST                2 (i)
             28 LOAD_CONST               1 (2)
             31 BINARY_MULTIPLY     
             32 CALL_FUNCTION            1
             35 POP_TOP             
             36 JUMP_ABSOLUTE           13
        >>   39 POP_BLOCK           
 20     >>   40 LOAD_FAST                1 (alist)
             43 RETURN_VALUE 

通过字节码,可以看出来,list comprehension的指令更少,不需要建立列表变量,同时,也就无需取变量,

更不需要调用list的append函数(调用函数需要维护stack信息),也就比append要快。

查看Python的官方wiki的Loop页面,也有提到map和for loop中append的问题:

newlist = []
for word in oldlist:
    newlist.append(word.upper())

和:

newlist = map(str.upper, oldlist)

这里map要比for loop快,因为for loop是在解释器中执行的,而map则是编译好的C代码。

测试代码如下:

def ():
    """Stupid test function"""
    oldlist = 'abcde'
    newlist = []
    for word in oldlist:
        newlist.append(word.upper())
    return newlist
def test2():
    oldlist = 'abcde'
    return map(str.upper, oldlist)
if __name__ == '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test"))
    print('------')
    print(timeit.timeit("test2()", setup="from __main__ import test2"))

结果如下:

3.65194892883
------
2.49910998344
©2020 edoou.com   京ICP备16001874号-3