Python的字符串连接与str.join的速度有多慢?

Way*_*ner 61 python string list string-concatenation

由于我在这个帖子的回答中的评论,我想知道+=运营商和运营商之间的速度差异''.join()

那两者之间的速度比较是什么?

Dom*_*mra 85

来自:高效字符串连接

方法1:

def method1():
  out_str = ''
  for num in xrange(loop_count):
    out_str += 'num'
  return out_str
Run Code Online (Sandbox Code Playgroud)

方法4:

def method4():
  str_list = []
  for num in xrange(loop_count):
    str_list.append('num')
  return ''.join(str_list)
Run Code Online (Sandbox Code Playgroud)

现在我意识到它们并不具有严格的代表性,并且第四种方法在迭代并加入每个项目之前附加到列表中,但这是一个公平的指示.

字符串连接比串联快得多.

为什么?字符串是不可变的,不能在适当的位置进行更改.要改变一个,需要创建一个新的表示(两者的串联).

替代文字

  • 从PEP 8开始:"例如,不要依赖CPython为a + = b或a = a + b形式的语句有效实现就地字符串连接.这些语句在Jython中运行得更慢.在库的性能敏感部分,应该使用'.join()形式.这将确保连接在各种实现中以线性时间发生." (9认同)
  • -1.string.join和+ concatenation之间的速度差没有固定的比率,因为它们具有完全不同的**增长率**/大的复杂度.随着要连接的字符串数量的增长,与字符串连接相比,string.join将具有更大和更大的余量. (5认同)
  • 好吧,我本来就是回答这个问题(因此标签),但看起来你打败了我!+1,特别是对于有用的链接! (3认同)
  • @Wayne:*有用的链接*是从您链接到的问题中复制的! (2认同)

Jul*_*les 11

现有的答案写得非常好,经过研究,但这是 Python 3.6 时代的另一个答案,因为现在我们有了文字字符串插值(AKA,f-strings):

>>> import timeit
>>> timeit.timeit('f\'{"a"}{"b"}{"c"}\'', number=1000000)
0.14618930302094668
>>> timeit.timeit('"".join(["a", "b", "c"])', number=1000000)
0.23334730707574636
>>> timeit.timeit('a = "a"; a += "b"; a += "c"', number=1000000)
0.14985873899422586
Run Code Online (Sandbox Code Playgroud)

使用 CPython 3.6.5 在 2012 款 Retina MacBook Pro 和 Intel Core i7 频率为 2.3 GHz 上执行的测试。

这绝不是任何正式的基准测试,但看起来使用f-strings 的性能与使用+=串联的性能大致相同;当然,欢迎任何改进的指标或建议。

  • 请参阅类似问题的答案:/sf/answers/94520261/ += 不应使用,其性能提升是一种幻觉。 (2认同)

Way*_*ner 6

我的原始代码是错误的,似乎+连接通常更快(特别是在较新的硬件上使用较新版本的Python)

时间如下:

Iterations: 1,000,000       
Run Code Online (Sandbox Code Playgroud)

Windows 7,Core i7上的Python 3.3

String of len:   1 took:     0.5710     0.2880 seconds
String of len:   4 took:     0.9480     0.5830 seconds
String of len:   6 took:     1.2770     0.8130 seconds
String of len:  12 took:     2.0610     1.5930 seconds
String of len:  80 took:    10.5140    37.8590 seconds
String of len: 222 took:    27.3400   134.7440 seconds
String of len: 443 took:    52.9640   170.6440 seconds
Run Code Online (Sandbox Code Playgroud)

Windows 7,Core i7上的Python 2.7

String of len:   1 took:     0.7190     0.4960 seconds
String of len:   4 took:     1.0660     0.6920 seconds
String of len:   6 took:     1.3300     0.8560 seconds
String of len:  12 took:     1.9980     1.5330 seconds
String of len:  80 took:     9.0520    25.7190 seconds
String of len: 222 took:    23.1620    71.3620 seconds
String of len: 443 took:    44.3620   117.1510 seconds
Run Code Online (Sandbox Code Playgroud)

在Linux Mint上,Python 2.7,一些较慢的处理器

String of len:   1 took:     1.8840     1.2990 seconds
String of len:   4 took:     2.8394     1.9663 seconds
String of len:   6 took:     3.5177     2.4162 seconds
String of len:  12 took:     5.5456     4.1695 seconds
String of len:  80 took:    27.8813    19.2180 seconds
String of len: 222 took:    69.5679    55.7790 seconds
String of len: 443 took:   135.6101   153.8212 seconds
Run Code Online (Sandbox Code Playgroud)

以下是代码:

from __future__ import print_function
import time

def strcat(string):
    newstr = ''
    for char in string:
        newstr += char
    return newstr

def listcat(string):
    chars = []
    for char in string:
        chars.append(char)
    return ''.join(chars)

def test(fn, times, *args):
    start = time.time()
    for x in range(times):
        fn(*args)
    return "{:>10.4f}".format(time.time() - start)

def testall():
    strings = ['a', 'long', 'longer', 'a bit longer', 
               '''adjkrsn widn fskejwoskemwkoskdfisdfasdfjiz  oijewf sdkjjka dsf sdk siasjk dfwijs''',
               '''this is a really long string that's so long
               it had to be triple quoted  and contains lots of
               superflous characters for kicks and gigles
               @!#(*_#)(*$(*!#@&)(*E\xc4\x32\xff\x92\x23\xDF\xDFk^%#$!)%#^(*#''',
              '''I needed another long string but this one won't have any new lines or crazy characters in it, I'm just going to type normal characters that I would usually write blah blah blah blah this is some more text hey cool what's crazy is that it looks that the str += is really close to the O(n^2) worst case performance, but it looks more like the other method increases in a perhaps linear scale? I don't know but I think this is enough text I hope.''']

    for string in strings:
        print("String of len:", len(string), "took:", test(listcat, 1000000, string), test(strcat, 1000000, string), "seconds")

testall()
Run Code Online (Sandbox Code Playgroud)