python list comprehension vs + =

het*_*fan 2 python performance list-comprehension augmented-assignment

今天我试图找到一个方法,在python中对字符串进行一些处理.一些比我说的高级程序员不使用+=但使用''.join()我也可以在例如http://wiki.python.org/moin/PythonSpeed/#Use_the_best_algorithms_and_fastest_tools中阅读.但是我自己测试了这个并且发现了一些奇怪的结果(这不是我想要再猜测它们但是我想要站立).想法是,如果有一个"This is \"an example text\"包含空格的字符串"字符串应该被转换为Thisis"an example text"containingspaces空格被删除,但只在引号之外.

我测量了我的算法的两个不同版本的性能,使用了''.join(list)一个和一个+=

import time

#uses '+=' operator
def strip_spaces ( s ):
    ret_val = ""
    quote_found = False
    for i in s:
        if i == '"':
            quote_found = not quote_found

        if i == ' ' and quote_found == True:
            ret_val += i

        if i != ' ':
            ret_val += i
    return ret_val

#uses "".join ()   
def strip_spaces_join ( s ):
    #ret_val = ""
    ret_val = []
    quote_found = False
    for i in s:
        if i == '"':
            quote_found = not quote_found

        if i == ' ' and quote_found == True:
            #ret_val = ''.join( (ret_val, i) )
            ret_val.append(i)

        if i != ' ':
            #ret_val = ''.join( (ret_val,i) )
            ret_val.append(i)
    return ''.join(ret_val)


def time_function ( function, data):
    time1 = time.time();
    function(data)
    time2 = time.time()
    print "it took about {0} seconds".format(time2-time1)
Run Code Online (Sandbox Code Playgroud)

在我的机器上,这产生了这个输出,对于算法使用有一个小优势 +=

print '#using += yields ', timeit.timeit('f(string)', 'from __main__ import string, strip_spaces as f', number=1000)
print '#using \'\'.join() yields ', timeit.timeit('f(string)', 'from __main__ import string, strip_spaces_join as f', number=1000)
Run Code Online (Sandbox Code Playgroud)

与timeit计时时:

#using += yields  0.0130770206451
#using ''.join() yields  0.0108470916748
Run Code Online (Sandbox Code Playgroud)

差别很小.但是为什么''.join()没有明确地执行使用的功能+=,但是'.join()版本似乎有一个小优势.我使用python-2.7.3在Ubuntu 12.04上测试了这个

Mar*_*ers 8

比较算法时,请使用正确的方法; 使用该timeit模块消除CPU利用率和交换的波动.

timeit节目有两种方法之间的差别不大,但是''.join()快:

>>> s = 1000 * string
>>> timeit.timeit('f(s)', 'from __main__ import s, strip_spaces as f', number=100)
1.3209099769592285
>>> timeit.timeit('f(s)', 'from __main__ import s, strip_spaces_join as f', number=100)
1.2893600463867188
>>> s = 10000 * string
>>> timeit.timeit('f(s)', 'from __main__ import s, strip_spaces as f', number=100)
14.545105934143066
>>> timeit.timeit('f(s)', 'from __main__ import s, strip_spaces_join as f', number=100)
14.43651008605957
Run Code Online (Sandbox Code Playgroud)

函数中的大部分工作是循环遍历每个字符并测试引号和空格,而不是字符串连接本身.此外,该''.join()变体做了更多的工作; 您首先将元素附加到列表中(这将替换+=字符串连接操作),然后使用结束时将这些值连接起来''.join().而且这种方法仍然有点快.

您可能想要删除正在进行的工作以比较连接部分:

def inplace_add_concatenation(s):
    res = ''
    for c in s:
        res += c

def str_join_concatenation(s):
    ''.join(s)
Run Code Online (Sandbox Code Playgroud)

这表现了:

>>> s = list(1000 * string)
>>> timeit.timeit('f(s)', 'from __main__ import s, inplace_add_concatenation as f', number=1000)
6.113742113113403
>>> timeit.timeit('f(s)', 'from __main__ import s, str_join_concatenation as f', number=1000)
0.6616439819335938
Run Code Online (Sandbox Code Playgroud)

这表明''.join()串联仍然是一个赫克了很多的速度比+=.速度差异在于循环; s在这两种情况下都是一个列表,但是''.join()循环遍历C中的值,而另一个版本必须在Python中循环它.这在这里有所不同.