像C#中的StringBuilder这样的Python字符串类?


Answers:


102

没有一对一的关联。对于非常好的文章,请参见Python中的高效字符串连接

使用Python编程语言构建长字符串有时会导致运行速度非常慢。在本文中,我研究了各种字符串连接方法的计算性能。


27
请注意,本文是基于Python 2.2编写的。在现代版本的Python中,测试的结果可能会有所不同(CPython通常可以成功地优化串联,但是您不想在重要的代码中依赖它),并且值得考虑使用他使用列表理解的生成器表达式。
Mike Graham 2010年

4
最好在该文章中引入一些重点,至少要包括两个实现(以避免链接失效问题)。
jpmc26 2014年

3
方法1:根据以下@ Antoine-tran的测试,结果字符串+ = appendString是最快的
Justas 2015年

5
您的报价根本无法回答问题。请在答案中包括相关部分,以符合新准则。
基金莫妮卡的诉讼

27

我使用了Oliver Crow的代码(由Andrew Hare给出的链接),并对其进行了一些修改以适应Python 2.7.3。(通过使用timeit包)。我在个人计算机Lenovo T61、6GB RAM,Debian GNU / Linux 6.0.6(挤压)上运行。

这是10,000次迭代的结果:

方法1:0.0538418292999秒
处理大小4800 kb
方法2:0.22602891922秒
处理大小4960 kb
method3:0.0605459213257秒
处理大小4980 kb
method4:0.0544030666351秒
处理大小5536 kb
method5:0.0551080703735秒
处理大小5272 kb
method6:0.0542731285095秒
处理大小5512 kb

并且进行了5,000,000次迭代(方法2被忽略了,因为它运行得太慢了,就像永远一样):

方法1:5.88603997231秒
处理大小37976 kb
方法3:8.40748500824秒
处理大小38024 kb
方法4:7.96380496025秒
程序大小321968 kb
方法5:8.03666186333秒
处理大小71720 kb
方法6:6.68192911148秒
处理大小38240 kb

很明显,Python的人在优化字符串连接方面做得非常出色,正如Hoare所说:“过早的优化是万恶之源” :-)



5
避免脆弱的,依赖于解释程序的优化不是过早的优化。如果您想移植到PyPy或冒险遇到许多微妙的失败案例之一进行优化,请以正确的方式做事。
Veedrac

1
看起来方法1更易于编译器优化。
mbomb007'2015-04-29

24

依靠编译器优化是脆弱的。接受的答案中链接的基准和Antoine-tran给出的数字不可信。安德鲁·黑尔(Andrew Hare)错误地repr在其方法中包含了一个调用。这会平均降低所有方法的速度,但会掩盖构建字符串的实际代价。

使用join。它非常快速且更强大。

$ ipython3
Python 3.5.1 (default, Mar  2 2016, 03:38:02) 
IPython 4.1.2 -- An enhanced Interactive Python.

In [1]: values = [str(num) for num in range(int(1e3))]

In [2]: %%timeit
   ...: ''.join(values)
   ...: 
100000 loops, best of 3: 7.37 µs per loop

In [3]: %%timeit
   ...: result = ''
   ...: for value in values:
   ...:     result += value
   ...: 
10000 loops, best of 3: 82.8 µs per loop

In [4]: import io

In [5]: %%timeit
   ...: writer = io.StringIO()
   ...: for value in values:
   ...:     writer.write(value)
   ...: writer.getvalue()
   ...: 
10000 loops, best of 3: 81.8 µs per loop

是的,该repr调用支配了运行时,但没有必要将错误设为个人。
亚历克斯·雷肯

3
@AlexReinking对不起,没有任何个人含义。我不确定是什么使您认为它是私人的。但是,如果使用了他们的名字,我只会使用这些名字来指代用户的答案(与用户名匹配,不确定是否有更好的方法)。
GrantJ

1
分隔数据初始化和串联操作的良好时序示例
aiodintsov

19

Python具有满足类似目的的几件事:

  • 从片段构建大字符串的一种常用方法是增长字符串列表,并在完成后将其加入。这是一个常用的Python习惯用法。
    • 要构建包含格式化数据的字符串,您需要单独进行格式化。
  • 为了在字符级别插入和删除,您将保留一个长度为一的字符串列表。(要通过字符串进行此操作,list(your_string)您可以调用。您也可以UserString.MutableString为此使用a 。
  • (c)StringIO.StringIO 对于原本会占用文件的内容很有用,但对于一般的字符串构建则没什么用。

10

从上面使用方法5(伪文件),我们可以获得非常好的性能和灵活性

from cStringIO import StringIO

class StringBuilder:
     _file_str = None

     def __init__(self):
         self._file_str = StringIO()

     def Append(self, str):
         self._file_str.write(str)

     def __str__(self):
         return self._file_str.getvalue()

现在使用它

sb = StringBuilder()

sb.Append("Hello\n")
sb.Append("World")

print sb


-1

没有显式的类似物-我认为您应该使用字符串串联(可能如前所述进行优化)或第三方类(我怀疑它们效率更高)-python中的列表是动态类型的,因此无法快速工作char []用于缓冲区(我假设)。由于许多语言中的字符串固有特性(不可变性),类似Stringbuilder的类不是过早的优化-允许进行许多优化(例如,为片段/子字符串引用相同的缓冲区)。类似于Stringbuilder / stringbuffer / stringstream的类的工作比连接字符串(产生许多仍需要分配和垃圾回收的小型临时对象)甚至字符串格式的类似于printf的工具要快得多,不需要解释格式化模式的开销,这对于很多格式调用。


-4

如果您在这里寻找Python中的快速字符串连接方法,则不需要特殊的StringBuilder类。简单的串联也可以正常工作,而不会降低C#中的性能。

resultString = ""

resultString += "Append 1"
resultString += "Append 2"

有关性能结果,请参见Antoine-tran的答案

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.