fileinput.input() 的 inplace=True 参数将原文件重命名为备份(默认.bak),并重定向 stdout 到原文件名,使 print() 输出写入新文件;必须配合 print(..., end='') 使用,避免双换行,且需用 fileinput.hook_encoded() 处理编码问题。

fileinput.input() 的 inplace=True 参数到底改了什么
它不是“真正原地修改”,而是把原文件重命名为 filename.bak,再把 stdout 重定向到原文件名——所有 print() 输出都会写进新文件。这意味着:你不能用 open() 手动读写,必须依赖 fileinput 的迭代和 print() 输出。
常见错误是边读边用 open(filename, 'w') 覆盖,结果清空文件或破坏迭代流。正确做法只有一条路:fileinput.input(files, inplace=True) + print() 替代 print() 原始行。
- 必须用
inplace=True,否则输出到终端,不写文件 - 默认备份后缀是
.bak,可通过backup='.orig'修改 - 如果不想留备份,设
backup=''(空字符串),但出错时无法回滚 -
sys.stdout在inplace=True下被临时重定向,所以print()才能生效
逐行处理时如何安全替换内容而不丢数据
直接 print(line) 会多一个换行(因为 line 已含 \n),导致空行。这是最常踩的坑。
正确做法是用 print(line, end='') 消除重复换行;若要替换某行,先做字符串处理,再统一 print(..., end='') 。
立即学习“Python免费学习笔记(深入)”;
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
import fileinput
<p>for line in fileinput.input(['a.txt', 'b.txt'], inplace=True, backup='.bak'):
if 'old' in line:
line = line.replace('old', 'new')
print(line, end='') # 关键:end='' 避免双换行
-
line总是以\n结尾(包括最后一行,即使文件没换行也会补) - 不要用
line.strip()后再print(),会丢失原始缩进和空行 - 想跳过某行?直接 continue,不
print()即可 - 想插入新行?
print('new line', end='\n'),注意显式控制换行
跨平台下文件编码与换行符的兼容性问题
fileinput 默认用系统默认编码(Windows 是 cp1252,Linux/macOS 是 utf-8),读取 UTF-8 文件可能报 UnicodeDecodeError。它也不处理换行符标准化(\r\n vs \n)。
Python 3.8+ 支持 openhook 参数,可用 fileinput.hook_encoded('utf-8') 统一解码;但注意:这仅控制读取,写入仍按系统默认编码——所以最好显式指定写入编码。
- 安全做法:用
openhook=fileinput.hook_encoded('utf-8')读,再用print(..., end='', file=sys.stdout)(此时 stdout 已被重定向,编码由底层决定) - 更稳妥的方式是放弃
inplace=True,改用临时文件 +os.replace(),自行控制编码 - Windows 上处理
\r\n文件时,line末尾是\r\n,print(line, end='')会保留它;无需额外处理
如何判断当前正在处理哪个文件及行号
fileinput 提供 fileinput.filename() 和 fileinput.filelineno(),但要注意:它们只在进入新文件或新行后才更新,不能在循环外提前调用。
典型误用是在 for line in ...: 外查 filename(),结果返回 None 或上一个文件名。
import fileinput <p>for line in fileinput.input(['x.py', 'y.py'], inplace=True): if fileinput.filename() == 'x.py' and 'def' in line: line = '# ' + line print(line, end='')
-
fileinput.filename()返回当前正在迭代的文件路径(绝对路径需os.path.abspath()自行处理) -
fileinput.filelineno()是当前文件内的行号(从 1 开始);fileinput.lineno()是全局总行号 - 首次进入循环时,
filename()才有效;循环前调用会返回None - 修改多个文件时,靠
filename()分支处理是最可靠的方式,别依赖文件顺序
实际用起来,最麻烦的不是语法,而是备份策略和编码一致性——尤其当脚本要跑在不同机器上时,backup='' 看似省事,一旦写坏就真没了。

















