在Python中连接string的首选方法是什么?

由于Python的string不能改变,我想知道如何更有效地连接string?

我可以这样写:

 s += stringfromelsewhere 

或者像这样:

 s = [] s.append(somestring) later s = ''.join(s) 

在写这个问题的时候,我发现了一篇关于这个话题的好文章。

http://www.skymind.com/~ocrow/python_string/

但它是Python 2.x.所以这个问题会在Python 3中做一些改变吗?

将string附加到stringvariables的最佳方法是使用++= 。 这是因为它的可读性和快速性。 他们也是一样快,你select哪一个是品味的问题,后者是最常见的。 以下是timeit模块的计时:

 a = a + b: 0.11338996887207031 a += b: 0.11040496826171875 

但是,那些build议拥有列表并追加到列表中,然后join这些列表的人,是这样做的,因为与扩展string相比,将string附加到列表大概是非常快的。 在某些情况下,这可能是事实。 在这里,例如,一个string的一百万个附加,首先是一个string,然后是一个列表:

 a += b: 0.10780501365661621 a.append(b): 0.1123361587524414 

好的,即使结果string是一百万个字符长,追加仍然更快。

现在让我们尝试追加千string十万次:

 a += b: 0.41823482513427734 a.append(b): 0.010656118392944336 

结束string,因此,最终大约100MB长。 这很慢,附加到列表要快得多。 那个时机不包括最后的a.join() 。 那要多久呢?

 a.join(a): 0.43739795684814453 

Oups。 即使在这种情况下,append / join也变慢。

那么这个build议是从哪里来的? Python 2?

 a += b: 0.165287017822 a.append(b): 0.0132720470428 a.join(a): 0.114929914474 

那么,如果你使用的是非常长的string(通常不是,那么你会得到一个内存为100MB的string?

但真正的重头戏是Python 2.3。 在哪里我不会告诉你时机,因为它太慢了,还没有完成。 这些testing突然花费几分钟 。 除了追加/join之外,这与后来的python一样快。

对。 Python的string连接在石器时代非常缓慢。 但在2.4上已经不是了(至lessPython 2.4.7),所以使用append / join的build议在2008年变得过时了,当时Python 2.3停止了更新,你应该停止使用它。 🙂

(更新:当我更仔细地进行testing时发现,在Python 2.3中,对于两个string使用++=会更快。使用''.join()的build议必须是一个误解)

但是,这是CPython。 其他的实现可能有其他的关注。 这就是为什么过早优化是万恶之源的又一个原因。 除非你先测量它,否则不要使用“更快”的技术。

因此,做“string连接”的“最佳”版本是使用+或+ = 。 如果这对你来说太慢了,这是不太可能的,那么做别的事情。

那么为什么我在代码中使用了很多append / join? 因为有时它更清晰。 特别是当你应该连接在一起的时候,应该用空格或逗号或换行符分开。

如果你连接了很多值,那么两者都不是。 追加名单是昂贵的。 你可以使用StringIO。 特别是如果你是通过很多操作来构build它的话。

 from cStringIO import StringIO # python3: from io import StringIO buf = StringIO() buf.write('foo') buf.write('foo') buf.write('foo') buf.getvalue() # 'foofoofoo' 

如果你已经有一个完整的列表从其他操作返回给你,那么只需使用''.join(aList)

从python常见问题解答: 什么是连接多个string最有效的方法?

str和bytes对象是不可变的,因此将许多string连接在一起是无效的,因为每个连接都会创build一个新的对象。 在一般情况下,总运行时间成本是总string长度的二次方。

为了积累许多str对象,推荐的习惯用法是把它们放到一个列表中,并在最后调用str.join():

 chunks = [] for s in my_strings: chunks.append(s) result = ''.join(chunks) 

(另一个合理有效的习惯用法是使用io.StringIO)

为了积累许多字节对象,推荐的习惯用法是使用in-place级联(+ =运算符)来扩展一个bytearray对象:

 result = bytearray() for b in my_bytes_objects: result += b 

编辑:我很愚蠢,结果往后粘贴,看起来像附加到列表比cStringIO快。 我还添加了对bytearray / str concat的testing,以及使用较大string的较大列表进行的第二轮testing。 (python 2.7.3)

ipythontesting大string列表的例子

 try: from cStringIO import StringIO except: from io import StringIO source = ['foo']*1000 %%timeit buf = StringIO() for i in source: buf.write(i) final = buf.getvalue() # 1000 loops, best of 3: 1.27 ms per loop %%timeit out = [] for i in source: out.append(i) final = ''.join(out) # 1000 loops, best of 3: 9.89 ms per loop %%timeit out = bytearray() for i in source: out += i # 10000 loops, best of 3: 98.5 µs per loop %%timeit out = "" for i in source: out += i # 10000 loops, best of 3: 161 µs per loop ## Repeat the tests with a larger list, containing ## strings that are bigger than the small string caching ## done by the Python source = ['foo']*1000 # cStringIO # 10 loops, best of 3: 19.2 ms per loop # list append and join # 100 loops, best of 3: 144 ms per loop # bytearray() += # 100 loops, best of 3: 3.8 ms per loop # str() += # 100 loops, best of 3: 5.11 ms per loop 

推荐的方法仍然是使用追加和连接。

如果要连接的string是文字,请使用string连接

 re.compile( "[A-Za-z_]" # letter or underscore "[A-Za-z0-9_]*" # letter, digit or underscore ) 

如果您想要对部分string进行注释(如上所述),或者想要将原始string或三重引号用于部分字面而不是全部,则这非常有用。

由于这发生在语法层,它使用零连接运算符。

虽然有些过时,但像Pythonista一样代码:习惯Python推荐在本节中通过+ join() 。 就像PythonSpeedPerformanceTips在string连接部分一样,有以下免责声明:

关于Python的更高版本,本节的准确性有争议。 在CPython 2.5中,string连接速度相当快,但这可能不适用于其他Python实现。 请参阅ConcatenationTestCode进行讨论。

使用“+”string连接是稳定性和交叉实现方面的串联方法,因为它不支持所有的值。 PEP8标准不鼓励这种做法,鼓励使用format(),join()和append()来长期使用。

你也可以使用这个(更高效)。 ( https://softwareengineering.stackexchange.com/questions/304445/why-is-s-better-than-for-concatenation

 s += "%s" %(stringfromelsewhere) 

你写这个函数

 def str_join(*args): return ''.join(map(str, args)) 

那么你可以随便拨打电话

 str_join('Pine') # Returns : Pine str_join('Pine', 'apple') # Returns : Pineapple str_join('Pine', 'apple', 3) # Returns : Pineapple3