writelines() 不自动换行是设计使然,它仅原样写入字符串列表,不添加任何分隔符;需手动为每行添加 '\n' 才能实现换行效果。

写入多行数据时 writelines() 不自动换行,这是设计使然
writelines() 的名字有误导性——它只是把每个字符串原样写入,不加任何分隔符。你传入 ['a', 'b', 'c'],结果就是 abc,不是三行。
常见错误现象:with open('out.txt', 'w') as f: f.writelines(['line1', 'line2']) → 文件里只有一行 line1line2,看着像“没生效”。
- 必须手动给每行末尾加上
\n(或\r\n,视平台而定) - 推荐统一用
\n,Python 在文本模式下会按系统自动转换(Windows 写入时转成\r\n) - 别用
str.splitlines(keepends=True)拆原始字符串再写,容易漏掉末尾无换行的行
最稳妥的写法:用列表推导预处理每行加 \n
场景:你有一组待写入的字符串,比如日志、配置项、爬虫结果,要保持一行一条。
直接在传入前补换行,比写循环更简洁、不易错:
立即学习“Python免费学习笔记(深入)”;
lines = ['apple', 'banana', 'cherry']
with open('fruits.txt', 'w') as f:
f.writelines([line + '\n' for line in lines])注意:[line + '\n' 不能写成 [f'{line}\n',除非你确定 line 本身不含 \n;否则可能写出空行或错位。
- 如果
lines里某些元素已含结尾换行,先用line.rstrip('\r\n')清理再加\n - 不要用
'\n'.join(lines) + '\n'再传给writelines()—— 这等于只传一个大字符串,失去writelines()的流式优势,且对超长数据有内存风险
想追加写入且避免开头多出空行?检查最后一行是否已有换行
使用 'a' 模式时,如果上一次写入没以 \n 结尾,新内容会接在末尾同一行,比如:
# 假设文件当前是 "first\nsecond" f.writelines(['third\n']) # → "first\nsecondthird\n" ❌
解决办法不是每次打开都读一遍末尾,而是写之前判断并补:
- 用
os.path.getsize(path) > 0快速判断文件非空 - 用
f.seek(0, 2)定位到末尾,再f.seek(-1, 1)回退一位读字符(需小心空文件或单字符文件) - 更简单:统一在每次写入前,确保首行前面有换行 —— 即写
['\n'] + [line + '\n' for line in new_lines],但要注意首次写入时开头会多一个空行
实际中,多数场景直接接受“追加内容从新行开始”,就老老实实每行自己带 \n,靠人肉保证输入干净。
writelines() 和 write() + join() 性能差别很小,别为这点优化纠结
有人觉得 writelines() 是“批量写”,一定比 write('\n'.join(lines)) 快。其实 CPython 下两者最终都走同一个底层 write 调用,差异在 Python 层拼接开销。
性能影响:
- 当
lines很少( - 当
lines极多(>10⁵)且每行很长:'\n'.join()会构造一个巨大字符串,吃内存;writelines()流式写更稳 - 但真到这个量级,该考虑用
csv.writer、json.dump或分块写入了,而不是卡在writelines()选型上
真正容易被忽略的是:Windows 记事本打不开无换行结尾的文件最后一行——不是程序错了,是编辑器显示逻辑。所以哪怕业务上不依赖换行,也建议最后一行显式加 \n。










