python 列表理解与 +=

标签 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\" containing spaces"该字符串应该转换为 This"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)

在我的机器上,这产生了这个输出,对于使用 +=

的算法来说有一个小优势
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)

当用 timeit 计时时:

#using += yields  0.0130770206451
#using ''.join() yields  0.0108470916748

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

最佳答案

在比较算法时一定要使用正确的方法;使用 timeit module以消除 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

函数中的大部分工作是遍历每个字符并测试引号和空格,而不是字符串连接本身。此外,''.join() 变体做了更多的工作;您首先将元素附加到列表(这取代了 += 字符串连接操作),然后您在末尾使用 '' 连接这些值。加入()。而且该方法仍然稍微快一些。

您可能想要剥离正在完成的工作以比较只是连接部分:

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

def str_join_concatenation(s):
    ''.join(s)

显示:

>>> 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

这表明 ''.join() 连接仍然比 += 快很多 heck。速度差异在于循环; s 在这两种情况下都是一个列表,但是 ''.join() 循环遍历 C 中的值,而另一个版本必须完成它在 Python 中循环的所有操作。这让一切变得不同。

关于python 列表理解与 +=,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16781032/

相关文章:

python - 如何使用 Prefect 在 AKS 上部署 Kubernetes 作业

java - 什么对性能更好?列表,还是从数据库获取信息?

java - 最小化 Java 线程上下文切换开销

python - 列表理解导致 "name ... is not defined"错误

python - 在 Pandas 中计算每月的最后一个星期五

python - 函数式编程方法,或大多数 Pythonic 方法,一次使用两个相邻变量遍历数组

python - 结束循环正在终止线程

PHP 什么时候应该执行 shell,而不是内部 PHP 函数。表现?安全?

python - 列表理解期间的异常。中间结果是否保存在任何地方?

python - 列表理解表达式不显示任何值而不是子列表