假设永远不应该使用 + 进行字符串拼接,而始终使用 ''.join 可能是一种错误的观念。虽然使用 + 会创建不必要的临时复制不可变的字符串对象,但另一个经常被忽略的事实是,在循环中调用 join 通常会增加函数调用的开销。让我们看一个例子。
创建两个列表,一个来自链接的 SO 问题,另一个是更大的虚构列表。
>>> myl1 = ['A','B','C','D','E','F']
>>> myl2=[chr(random.randint(65,90)) for i in range(0,10000)]
让我们创建两个函数,UseJoin
和 UsePlus
来使用各自的 join
和 +
功能。
>>> def UsePlus():
return [myl[i] + myl[i + 1] for i in range(0,len(myl), 2)]
>>> def UseJoin():
[''.join((myl[i],myl[i + 1])) for i in range(0,len(myl), 2)]
让我们使用第一个列表运行 timeit
>>> myl=myl1
>>> t1=timeit.Timer("UsePlus()","from __main__ import UsePlus")
>>> t2=timeit.Timer("UseJoin()","from __main__ import UseJoin")
>>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=100000)/100000)
2.48 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=100000)/100000)
2.61 usec/pass
>>>
它们几乎具有相同的运行时间。
让我们使用cProfile。
>>> myl=myl2
>>> cProfile.run("UsePlus()")
5 function calls in 0.001 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.001 0.001 0.001 0.001 <pyshell
1 0.000 0.000 0.001 0.001 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {len}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 0.000 0.000 {range}
>>> cProfile.run("UseJoin()")
5005 function calls in 0.029 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.015 0.015 0.029 0.029 <pyshell
1 0.000 0.000 0.029 0.029 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {len}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
5000 0.014 0.000 0.014 0.000 {method 'join' of 'str' objects}
1 0.000 0.000 0.000 0.000 {range}
看起来使用Join会导致不必要的函数调用,这可能会增加开销。
现在回到问题。是否应该在所有情况下都不鼓励使用+
而使用join
?
我认为不是,应该考虑以下几点:
- 问题字符串的长度
- 连接操作的次数
当然,在开发早期过度优化是有害的。
In [2]: %timeit "a"*80 + "b"*80
1000000 循环,最佳 3 次: 每个循环 356 纳秒
In [3]: %timeit "%s%s" % ("a"*80, "b"*80)
1000000 循环,最佳 3 次: 每个循环 907 纳秒
- Jakob Bowyer%
连接两个字符串a
和b
的速度相对较慢,而使用加号+
连接字符串的速度要快得多。在以上代码中,%timeit
函数用于多次测试代码的执行时间,并返回最佳执行时间和每轮循环执行的平均时间。在这个例子中,%timeit "%s%s" % (a, b)
表示测试字符串格式化操作符%
连接字符串的执行时间,%timeit a + b
表示测试使用加号+
连接字符串的执行时间。 - Jakob Bowyer__str__
的自动类型转换。请参见我的答案以获取示例。 - Izkata