python的字符串连接效率与准则

准则

学习了下Google的字符串连接准则,有如下三条:

  1. 简单字符串连接时,直接使用"+",例如:full_name = prefix + name
  2. 复杂的,尤其有格式化需求时,使用"%"进行格式化连接,例如:result = "result is %s:%d" % (name, score)
  3. 当有大量字符串拼接,尤其发生在循环体里时,使用"str.join"进行连接,例如:result = ''.join(names_tuple)

前两条出于代码美观考虑,后一条出于性能考虑。

测试

使用str.join和使用加号,两种方式在内存使用与性能方式到底有多大差别,写了段测试代码如下:

from time import time

all_str = []
for i in xrange(1, 10000):
    all_str.append('100100'*i)

result_str1 = ''
result_str2 = ''

t1 = time()

for i in all_str:
    result_str1 = result_str1 + i 

t2 = time()

tmp_tup = []
for i in all_str:
    tmp_tup.append(i)
result_str2 = ''.join(tmp_tup)

t3 = time()
print("time dist:%f:%f" % (t2-t1, t3-t2))

while 'y' != raw_input('quit?(y)'):
    pass

代码最开始产生大量字符串,然后先后使用加号和str.join进行连接, 并分别统计耗时,同时程序末尾不退出,以方便观察内存占用。

首先我们预估一下结果,使用加号进行连接,会导致反复产生新的字符串, 反复进行空间分配与字符串拷贝。而使用str.join会进行优化,不然也不会很多公司的规范里明令禁止使用加号,而强制使用str.join, 既然join的参数是一个数组,做内存的预估计与预分配,也是很容易进行的。 所以可以想到,加号的耗时应该会比str.join的耗时大很多。当然tmp_tup去引用all_str里的每一个元素,也会消耗一些时间, 之所以加这句代码,是因为加号会比str.join的使用灵活得多,往往要连接的字符串,都不是恰好直接来源于一个tuple。 关于内存使用,由于输入一样,输出一样,最终消耗的内存应该是一样,当然在执行中,内存占用的波动情况应该是不一样的。

某次真实测试结果是:

time dist:0.717386:0.668515

如上面的预估一样,确实str.join要快,最终内存消耗也是一样。但与预估不一致的是, 使用加号与使用str.join的耗时差距并不大,甚至有时,使用加号还会更快一些。

从python的手册里找到了答案,在cpython的实现里,2.4以前的版本里,字符串连接绝对不会是in-place拼接, 也就是说确实有大量的再分配再拷贝的操作,而后来版本就做了优化。

观点

很显然使用加号简洁清爽得多,而使用str.join,你得先把字符串都整到一个tuple或者list中去。 而且,python中的加号字符串连接,并不如我们想像中那么糟糕,跟实现版本有关。 当然还是建议遵守最开始提到的三条准则,大量字符串连接时优先使用str.join。

发表于 2014年08月12日 18:01   评论:0   阅读:4480  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo