Python字符串拼接:为何join在循环中比+=慢?用法是否有误?
字符串拼接:
+= vs ''.join()的性能疑问 我了解到CPython对a = a + b或a += b形式的字符串拼接有原地无拷贝优化,同时PEP8建议不要依赖该优化,推荐在性能敏感场景使用''.join()以保证多Python实现下的线性时间性能。我尝试用a = ''.join([a, b, c])替代a += b + c,但测试发现循环中join的性能远低于+=,测试代码及结果如下:
测试代码
import os import time if __name__ == "__main__": start_time = time.time() print("begin: %s " % (start_time)) s = "" for i in range(100000): s = s + str(i) + '3' time1 = time.time() print("end loop1: %s " % (time1 - start_time)) s2 = "" for i in range(100000): s2 += str(i) + '3' time2 = time.time() print("end loop2: %s " % (time2 - time1)) s3 = "" for i in range(100000): s3 = ''.join([s3, str(i), '3']) time3 = time.time() print("end loop3: %s " % (time3 - time2))
测试结果
~/testdir$ python --version Python 3.10.6 ~/testdir$ python concatenate.py begin: 1675268345.0761461 end loop1: 3.9019 end loop2: 0.0260 end loop3: 0.9289
请问我的join用法是否有误?
解答
你的join用法确实错了,这才导致性能远不如+=。
问题出在哪?
''.join()的核心优势是一次性计算所有待拼接片段的总长度,分配一次内存后完成所有内容拷贝,时间复杂度是O(n)。但你在循环里每次调用''.join([s3, str(i), '3']),相当于每次都要把之前已经拼接好的s3重新拷贝一遍——和未优化的a = a + b一样,时间复杂度变成了O(n²),自然性能拉胯。
正确的join用法
应该先把所有要拼接的片段收集到一个列表里,最后只调用一次''.join():
import time if __name__ == "__main__": start_time = time.time() print(f"begin: {start_time} ") # 原s = s + ... s = "" for i in range(100000): s = s + str(i) + '3' time1 = time.time() print(f"end loop1 (+): {time1 - start_time:.4f} ") # 原s2 += ... s2 = "" for i in range(100000): s2 += str(i) + '3' time2 = time.time() print(f"end loop2 (+=): {time2 - time1:.4f} ") # 错误的join用法 s3 = "" for i in range(100000): s3 = ''.join([s3, str(i), '3']) time3 = time.time() print(f"end loop3 (错误join): {time3 - time2:.4f} ") # 正确的join用法 parts = [] for i in range(100000): parts.append(str(i) + '3') s4 = ''.join(parts) time4 = time.time() print(f"end loop4 (正确join): {time4 - time3:.4f} ")
预期结果
运行后你会发现,正确的join用法性能和+=接近甚至持平(不同Python版本可能有细微差异),因为它真正发挥了join的线性时间优势。
额外说明
- CPython的
+=优化是特定实现细节:字符串本身不可变,但当变量是该字符串的唯一引用时,CPython会尝试原地扩容,避免重复拷贝。但其他Python实现(如PyPy、Jython)不一定支持这个优化。 - PEP8推荐
''.join()的原因是它在所有Python实现中都能保证线性时间性能,代码兼容性更强;如果你的代码只针对CPython,循环里用+=也能获得很好的性能。
内容的提问来源于stack exchange,提问作者Étienne
相关产品推荐
相关产品推荐

