
通过自定义支持 write() 方法的类作为 print(file=...) 的参数,可在不修改 print() 调用语法、不依赖外部命令(如 tee)的前提下,实现输出内容同步写入标准输出与文件。
通过自定义支持 `write()` 方法的类作为 `print(file=...)` 的参数,可在不修改 `print()` 调用语法、不依赖外部命令(如 `tee`)的前提下,实现输出内容同步写入标准输出与文件。
在 Python 中,print() 函数的 file 参数接受任意具有 .write(string) 方法的文本 I/O 对象(即符合 typing.TextIO 协议的对象)。我们可利用这一特性,构建一个轻量级的 MultiTextIO 类,它内部聚合多个目标输出流(如 sys.stdout 和一个打开的文件),并在每次调用 .write() 时将数据广播至所有流。
以下是完整、健壮的实现示例:
import sys
from typing import TextIO, List
class MultiTextIO:
def __init__(self, *fds: TextIO):
# 过滤掉 None 或不可写对象,提升容错性
self.fds: List[TextIO] = [fd for fd in fds if hasattr(fd, 'write') and callable(fd.write)]
def write(self, text: str) -> int:
# 返回写入总字符数(兼容 print 内部逻辑)
total = 0
for fd in self.fds:
n = fd.write(text)
total += n if isinstance(n, int) else 0
return total
def flush(self) -> None:
# 确保所有流及时刷新(print 默认不自动 flush,但可能被调用)
for fd in self.fds:
if hasattr(fd, 'flush'):
fd.flush()
# 使用示例
if __name__ == "__main__":
# 默认输出到 output.txt,也可通过命令行指定路径
output_path = sys.argv[1] if len(sys.argv) > 1 else "output.txt"
with open(output_path, "w", encoding="utf-8") as f:
multi_io = MultiTextIO(sys.stdout, f)
print("Hello, World!", file=multi_io)
print("This goes to both console and file.", file=multi_io)
# 注意:print 自动添加换行符,无需手动加 '\n'✅ 关键优势:
- 完全保持原生 print(..., file=...) 用法,零语法变更;
- 无外部进程依赖(如 tee),纯 Python 实现,跨平台安全;
- 支持任意数量的输出目标(如同时写入 stdout、日志文件、StringIO 缓冲区等);
- 显式实现了 flush() 方法,便于控制缓冲行为(尤其在长脚本或错误处理中很重要)。
⚠️ 注意事项:
- 打开文件建议使用 with 语句确保正确关闭;若需长期复用 MultiTextIO 实例,请自行管理文件生命周期;
- 所有目标流应为文本模式("w" 或 "a"),且编码一致(推荐显式指定 encoding="utf-8");
- print() 在写入后不会自动调用 flush(),如需实时可见(例如进度日志),可手动调用 multi_io.flush(),或设置 print(..., flush=True) —— 后者会间接触发 MultiTextIO.flush()。
该方案简洁、可扩展、符合 Python 的鸭子类型哲学,是生产环境中兼顾可读性与可靠性的推荐实践。

















