Python相当于Java StringBuffer?

时间:2013-11-12 10:00:48

标签: java python stringbuffer

Python中有什么像Java StringBuffer?由于字符串在Python中也是不可变的,因此在循环中编辑它们效率很低。

8 个答案:

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

由于没有特权,我不能对此发表评论。