Python 的字符串连接与 str.join 相比有多慢?

2025-01-13 08:52:00
admin
原创
133
摘要:问题描述:由于我在这个帖子上的回答中的评论,我想知道+=操作员和之间的速度差异是什么''.join()那么两者的速度对比如何呢?解决方案 1:来自:高效字符串连接方法 1:def method1(): out_str = '' for num in xrange(loop_count): ou...

问题描述:

由于我在这个帖子上的回答中的评论,我想知道+=操作员和之间的速度差异是什么''.join()

那么两者的速度对比如何呢?


解决方案 1:

来自:高效字符串连接

方法 1:

def method1():
  out_str = ''
  for num in xrange(loop_count):
    out_str += 'num'
  return out_str

方法 4:

def method4():
  str_list = []
  for num in xrange(loop_count):
    str_list.append('num')
  return ''.join(str_list)

现在我意识到它们并不是严格具有代表性的,并且第四种方法在迭代和连接每个项目之前会将其附加到列表中,但这是一个公平的迹象。

字符串连接比连接快得多。

为什么?字符串是不可变的,无法就地更改。要更改一个字符串,需要创建一个新的表示(将两者连接起来)。

替代文本

解决方案 2:

注意:此基准测试是非正式的,需要重新进行,因为它没有全面展示这些方法在处理实际较长的字符串时的性能。正如 @Mark Amery 在评论中提到的,+=并不像使用f-strings 那样可靠地快速,并且str#join在实际用例中速度也没有那么慢。

这些指标也可能因为后续 CPython 版本(尤其是 3.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

测试使用 CPython 3.6.5 在配备 2.3 GHz Intel Core i7 的 2012 Retina MacBook Pro 上进行。

解决方案 3:

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

具体时间如下:

Iterations: 1,000,000       

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

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

在 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

代码如下:

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
               @!#(*_#)(*$(*!#@&)(*Exc4x32xffx92x23xDFxDFk^%#$!)%#^(*#''',
              '''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()

解决方案 4:

如果我预期的不错,对于一个包含 k 个字符串、总共 n 个字符的列表,连接的时间复杂度应该是 O(nlogk),而经典连接的时间复杂度应该是 O(nk)。

这与合并 k 个排序列表的相对成本相同(有效方法是 O(nlkg),而类似于连接的简单方法是 O(nk) )。

解决方案 5:

如果我从算法的角度来说,如果你选择 [ += ],那么它会生成一个新对象,并且它将是 O(n)2。但是如果你使用 [ .join** ],那么它将是 O(n)。

解决方案 6:

我重写了最后一个答案,您能否就我的测试方式分享一下您的意见?

import time

start1 = time.clock()
for x in range (10000000):
    dog1 = ' and '.join(['spam', 'eggs', 'spam', 'spam', 'eggs', 'spam','spam', 'eggs', 'spam', 'spam', 'eggs', 'spam'])

end1 = time.clock()
print("Time to run Joiner = ", end1 - start1, "seconds")


start2 = time.clock()
for x in range (10000000):
    dog2 = 'spam'+' and '+'eggs'+' and '+'spam'+' and '+'spam'+' and '+'eggs'+' and '+'spam'+' and '+'spam'+' and '+'eggs'+' and '+'spam'+' and '+'spam'+' and '+'eggs'+' and '+'spam'

end2 = time.clock()
print("Time to run + = ", end2 - start2, "seconds")

注意:此示例使用 Python 3.5 编写,其中 range() 的作用类似于以前的 xrange()

我得到的输出:

Time to run Joiner =  27.086106206103153 seconds
Time to run + =  69.79100515996426 seconds

就我个人而言,我更喜欢''.join([])而不是'Plusser way',因为它更干净,更易读。

解决方案 7:

这就是愚蠢的程序被设计用来测试的:)

使用加号

import time

if __name__ == '__main__':
    start = time.clock()
    for x in range (1, 10000000):
        dog = "a" + "b"

    end = time.clock()
    print "Time to run Plusser = ", end - start, "seconds"

输出:

Time to run Plusser =  1.16350010965 seconds

现在加入....

import time
if __name__ == '__main__':
    start = time.clock()
    for x in range (1, 10000000):
        dog = "a".join("b")

    end = time.clock()
    print "Time to run Joiner = ", end - start, "seconds"

输出:

Time to run Joiner =  21.3877386651 seconds

因此,在 Windows 上的 python 2.6 上,我认为 + 比 join 快 18 倍:)

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2379  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1510  
  PLM(产品生命周期管理)系统在企业项目管理中扮演着至关重要的角色,它能够整合产品从概念设计到退役的全流程信息,提升协同效率,降低成本。然而,项目范围蔓延是项目管理过程中常见且棘手的问题,在PLM系统环境下也不例外。范围蔓延可能导致项目进度延迟、成本超支、质量下降等一系列不良后果,严重影响项目的成功交付。因此,如何在P...
plm项目经理是做什么   16  
  PLM(产品生命周期管理)系统在现代企业的产品研发与管理过程中扮演着至关重要的角色。它不仅仅是一个管理产品数据的工具,更能在利益相关者分析以及沟通矩阵设计方面提供强大的支持。通过合理运用PLM系统,企业能够更好地识别、理解和管理与产品相关的各类利益相关者,构建高效的沟通机制,从而提升产品开发的效率与质量,增强企业的市场...
plm是什么   20  
  PLM(产品生命周期管理)项目管理对于企业产品的全生命周期规划、执行与监控至关重要。在项目推进过程中,监控进度偏差是确保项目按时、按质量完成的关键环节。五维健康检查指标体系为有效监控PLM项目进度偏差提供了全面且系统的方法,涵盖了项目的多个关键维度,有助于及时发现问题并采取针对性措施。需求维度:精准把握项目基石需求维度...
plm项目管理软件   18  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用