Python等价于Java的StringBuffer?

Python中是否有像Java的StringBuffer一样的东西? 由于string在Python中也是不可变的,因此在循环中编辑它们将是低效的。

Python中的高效string连接是一个相当古老的文章,其主要的说法是,天真的连接比连接慢得多,因为这部分已经在CPython中进行了优化:

CPython实现细节:如果s和t都是string,那么一些Python实现(如CPython)通常可以对s = s + t或s + = tforms的分配进行就地优化。 在适用的情况下,这种优化使得二次运行时间不太可能。 这个优化是版本和实现相关的。 对于性能敏感的代码,最好使用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,但边缘
  • 列表parsing比循环更快
  • join生成器比join列表慢
  • 其他方法是没有用的(除非你正在做一些特别的事情)

取决于你想做什么。 如果你想要一个可变的序列,内buildlisttypes是你的朋友,从str到list和back都是这样简单的:

  mystring = "abcdef" mylist = list(mystring) mystring = "".join(mylist) 

如果你想使用for循环来构build一个大的string,Python的方法通常是build立一个string列表,然后用适当的分隔符(linebreak或者其他)将它们连接在一起。

否则,你也可以使用一些文本模板系统,或者一个parsing器或任何专门的工具是最适合的工作。

也许使用一个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' 

使用字节arrays的吸引力是它的内存效率和方便的语法。 它也可以比使用临时列表更快:

 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 

请注意,速度差异大部分归因于容器的创build:

 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 

以前提供的答案几乎总是最好的。 但是,有时这个string是跨越很多方法调用和/或循环build立起来的,所以build立一个行列表并join它们并不一定自然。 而且既然不能保证你使用的是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' 

这个链接可能对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 

只是一个testing我运行在python 3.6.2显示“join”仍然赢得大!

 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