Python中有什么像Java StringBuffer
?由于字符串在Python中也是不可变的,因此在循环中编辑它们效率很低。
答案 0 :(得分:61)
Efficient String Concatenation in Python是一篇相当古老的文章,它的主要陈述是天真的连接比连接慢得多,因为这部分已经在CPython中进行了优化:
CPython实现细节:如果s和t都是字符串,某些Python实现(如CPython)通常可以对s = s + t或s + = t形式的赋值执行就地优化。如果适用,此优化使得二次运行时间的可能性大大降低。此优化依赖于版本和实现。对于性能敏感的代码,最好使用str.join()方法,该方法确保跨版本和实现的一致的线性串联性能。 @ http://docs.python.org/2/library/stdtypes.html
我已经调整了一下他们的代码并在我的机器上得到了以下结果:
from cStringIO import StringIO
from UserString import MutableString
from array import array
import sys, timeit
def method1():
out_str = ''
for num in xrange(loop_count):
out_str += `num`
return out_str
def method2():
out_str = MutableString()
for num in xrange(loop_count):
out_str += `num`
return out_str
def method3():
char_array = array('c')
for num in xrange(loop_count):
char_array.fromstring(`num`)
return char_array.tostring()
def method4():
str_list = []
for num in xrange(loop_count):
str_list.append(`num`)
out_str = ''.join(str_list)
return out_str
def method5():
file_str = StringIO()
for num in xrange(loop_count):
file_str.write(`num`)
out_str = file_str.getvalue()
return out_str
def method6():
out_str = ''.join([`num` for num in xrange(loop_count)])
return out_str
def method7():
out_str = ''.join(`num` for num in xrange(loop_count))
return out_str
loop_count = 80000
print sys.version
print 'method1=', timeit.timeit(method1, number=10)
print 'method2=', timeit.timeit(method2, number=10)
print 'method3=', timeit.timeit(method3, number=10)
print 'method4=', timeit.timeit(method4, number=10)
print 'method5=', timeit.timeit(method5, number=10)
print 'method6=', timeit.timeit(method6, number=10)
print 'method7=', timeit.timeit(method7, number=10)
结果:
2.7.1 (r271:86832, Jul 31 2011, 19:30:53)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)]
method1= 0.171155929565
method2= 16.7158739567
method3= 0.420584917068
method4= 0.231794118881
method5= 0.323612928391
method6= 0.120429992676
method7= 0.145267963409
结论:
join
仍然胜过concat,但很少答案 1 :(得分:11)
取决于你想做什么。如果你想要一个可变序列,内置list
类型是你的朋友,从str到list并返回就像这样简单:
mystring = "abcdef"
mylist = list(mystring)
mystring = "".join(mylist)
如果你想使用for循环构建一个大字符串,pythonic方法通常是建立一个字符串列表,然后将它们与适当的分隔符(换行符或其他)连接在一起。
否则你也可以使用一些文本模板系统,或者解析器或任何专门用于工作的专用工具。
答案 2 :(得分:7)
也许使用bytearray:
In [1]: s = bytearray('Hello World')
In [2]: s[:5] = 'Bye'
In [3]: s
Out[3]: bytearray(b'Bye World')
In [4]: str(s)
Out[4]: 'Bye World'
使用bytearray的吸引力在于其内存效率和方便的语法。它也比使用临时列表更快:
In [36]: %timeit s = list('Hello World'*1000); s[5500:6000] = 'Bye'; s = ''.join(s)
1000 loops, best of 3: 256 µs per loop
In [37]: %timeit s = bytearray('Hello World'*1000); s[5500:6000] = 'Bye'; str(s)
100000 loops, best of 3: 2.39 µs per loop
请注意,速度的大部分差异可归因于容器的创建:
In [32]: %timeit s = list('Hello World'*1000)
10000 loops, best of 3: 115 µs per loop
In [33]: %timeit s = bytearray('Hello World'*1000)
1000000 loops, best of 3: 1.13 µs per loop
答案 3 :(得分:5)
以前提供的答案几乎总是最好的。但是,有时字符串是在许多方法调用和/或循环中构建的,因此构建行列表然后加入它们并不一定很自然。由于无法保证您使用CPython或CPython的优化将适用,因此另一种方法是使用print!
这是一个示例帮助程序类,虽然帮助程序类很简单并且可能是不必要的,但它用于说明该方法(Python 3):
import io
class StringBuilder(object):
def __init__(self):
self._stringio = io.StringIO()
def __str__(self):
return self._stringio.getvalue()
def append(self, *objects, sep=' ', end=''):
print(*objects, sep=sep, end=end, file=self._stringio)
sb = StringBuilder()
sb.append('a')
sb.append('b', end='\n')
sb.append('c', 'd', sep=',', end='\n')
print(sb) # 'ab\nc,d\n'
答案 4 :(得分:2)
此链接可能对python中的连接有用
http://pythonadventures.wordpress.com/2010/09/27/stringbuilder/
以上链接中的示例:
def g():
sb = []
for i in range(30):
sb.append("abcdefg"[i%7])
return ''.join(sb)
print g()
# abcdefgabcdefgabcdefgabcdefgab
答案 5 :(得分:2)
我只是在python 3.6.2上运行测试,显示“join”仍然赢得BIG!
from time import time
def _with_format(i):
_st = ''
for i in range(0, i):
_st = "{}{}".format(_st, "0")
return _st
def _with_s(i):
_st = ''
for i in range(0, i):
_st = "%s%s" % (_st, "0")
return _st
def _with_list(i):
l = []
for i in range(0, i):
l.append("0")
return "".join(l)
def _count_time(name, i, func):
start = time()
r = func(i)
total = time() - start
print("%s done in %ss" % (name, total))
return r
iterationCount = 1000000
r1 = _count_time("with format", iterationCount, _with_format)
r2 = _count_time("with s", iterationCount, _with_s)
r3 = _count_time("with list and join", iterationCount, _with_list)
if r1 != r2 or r2 != r3:
print("Not all results are the same!")
输出结果为:
with format done in 17.991968870162964s
with s done in 18.36879801750183s
with list and join done in 0.12142801284790039s
答案 6 :(得分:0)
我已经在Roee Gavirel的代码2中添加了其他测试,这些测试最终表明,将列表连接到字符串并不比s + =“ something”快。
结果:
Python 2.7.15rc1
Iterations: 100000
format done in 0.317540168762s
%s done in 0.151262044907s
list+join done in 0.0055148601532s
str cat done in 0.00391721725464s
Python 3.6.7
Iterations: 100000
format done in 0.35594654083251953s
%s done in 0.2868080139160156s
list+join done in 0.005924701690673828s
str cat done in 0.0054128170013427734s
f str done in 0.12870001792907715s
代码:
from time import time
def _with_cat(i):
_st = ''
for i in range(0, i):
_st += "0"
return _st
def _with_f_str(i):
_st = ''
for i in range(0, i):
_st = f"{_st}0"
return _st
def _with_format(i):
_st = ''
for i in range(0, i):
_st = "{}{}".format(_st, "0")
return _st
def _with_s(i):
_st = ''
for i in range(0, i):
_st = "%s%s" % (_st, "0")
return _st
def _with_list(i):
l = []
for i in range(0, i):
l.append("0")
return "".join(l)
def _count_time(name, i, func):
start = time()
r = func(i)
total = time() - start
print("%s done in %ss" % (name, total))
return r
iteration_count = 100000
print('Iterations: {}'.format(iteration_count))
r1 = _count_time("format ", iteration_count, _with_format)
r2 = _count_time("%s ", iteration_count, _with_s)
r3 = _count_time("list+join", iteration_count, _with_list)
r4 = _count_time("str cat ", iteration_count, _with_cat)
r5 = _count_time("f str ", iteration_count, _with_f_str)
if len(set([r1, r2, r3, r4, r5])) != 1:
print("Not all results are the same!")
答案 7 :(得分:0)
在最重要的答案中,“ Python中的有效字符串连接”中的链接不再链接至预期的页面(而是重定向到tensorflow.org)。 但是,此页中引用了确切代码的2004年页面可能代表了该页面https://waymoot.org/home/python_string/。
自Google出现以来,您可能已经看过它了:
efficient python StringBuilder
由于没有特权,我不能对此发表评论。