字符串拼接应优先用''.join()而非+或+=,因其预分配内存使时间复杂度从o(n²)降至o(n);但需避免构建大列表、确保元素为str,并在超大数据场景下考虑分段处理或流式写入。

字符串不可变性直接导致+在循环里变慢
每次执行 s = s + item,Python 都得新建一个字符串对象:先算总长度,再 malloc 一块新内存,把旧内容全拷过去,最后把 item 拷进去。拼第 9999 次时,要复制前 9998 次累积的所有字符——这不是“写法不够好”,而是内存复制量随次数平方增长。
实测拼接 10 万个短字符串:''.join(list) 耗时约 0.06 秒,s += item 循环耗时 0.49 秒;到 100 万次时,差距常拉到百倍级。
join() 的两步预分配机制才是关键
str.join() 不是“语法糖”,它底层走的是 C 实现的 string_join 函数,核心就两步:
- 先遍历一次输入(比如列表、生成器),累加所有元素的
len(),预估总内存需求 - 一次性
malloc出足够空间,再挨个memcpy字符串片段
时间复杂度从 O(n²) 降到 O(n),但前提是传给它的可迭代对象别拖后腿——比如写成 ''.join([x for x in huge_iter]),列表推导式本身就把内存吃光了,不是 join 慢,是你构建方式错了。
哪些情况其实不该用join
不是所有拼接都该无脑上 join(),关键看是否“在循环中动态累积大量片段”:
- 拼接项少于 5 个、且不来自循环时,
f'{a}{b}{c}'或first + ' ' + last更快也更清晰 -
'SELECT * FROM ' + table + ' WHERE id = ' + str(id)应直接改用f-string,而非转列表再join -
join()要求所有元素是str,传[1, 2, 3]会直接报TypeError: sequence item 0: expected str instance,得先'-'.join(str(x) for x in [1, 2, 3])
超大数据流下,拼成一个字符串本身就是错的
哪怕用了 join(),如果最终字符串达几百 MB,照样 OOM。这时真正该问的不是“怎么拼更快”,而是:“这个结果是否必须是一整个字符串?”
- 用
io.StringIO当缓冲区,边读边写,最后调.getvalue() - 直接写文件:
f.writelines(lines)(注意它不自动加换行) - 分段处理:按 1000 行一组,每组
join后写入文件,再清空列表
最容易被忽略的点,从来不是 join 怎么写,而是没想清楚:你真的需要把它拼成一个大字符串吗?
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











