如何在Python中实现类似Linux tee命令的同时输出与日志记录?
Python实现tee功能递归错误的原因及解决方法
错误原因
- 大概率是你在实现时替换了系统默认的
sys.stdout,同时在自定义的输出逻辑里直接调用了print()——而print()默认会使用被替换后的sys.stdout,导致无限递归调用,最终触发RecursionError。 - 举个典型的错误示例(你可能写了类似代码):
import sys class Tee: def __init__(self, filename): self.file = open(filename, 'a') sys.stdout = self def write(self, msg): self.file.write(msg) print(msg) # 这里调用print会再次触发write,无限递归 tee = Tee('log.txt') print('test')
解决方法
方法1:保留原始stdout,避免递归调用
不要用print(),直接调用保存的原始sys.stdout的write方法,彻底切断递归链:
import sys class Tee: def __init__(self, filename): self.file = open(filename, 'a', encoding='utf-8') self.original_stdout = sys.stdout sys.stdout = self def write(self, msg): # 写入日志文件 self.file.write(msg) # 输出到控制台(用原始stdout,不会触发递归) self.original_stdout.write(msg) # 强制刷新缓冲区,避免输出延迟 self.original_stdout.flush() self.file.flush() def flush(self): # 必须实现flush方法,否则部分场景下输出会卡住 self.original_stdout.flush() self.file.flush() # 使用示例 tee = Tee('log.txt') print('这条信息会同时输出到控制台和日志文件') # 用完记得恢复原始stdout,避免影响后续代码 sys.stdout = tee.original_stdout tee.file.close()
方法2:直接写专用输出函数(简单无坑)
如果不需要全局替换所有print,直接写个独立函数更省心,完全不会有递归问题:
def tee_print(msg, log_file='log.txt'): # 输出到控制台 print(msg) # 写入日志文件 with open(log_file, 'a', encoding='utf-8') as f: f.write(f'{msg}\n') # 使用示例 tee_print('这条信息同时出现在控制台和日志') tee_print('另一条测试信息', log_file='my_log.txt')
方法3:用上下文管理器(优雅且安全)
用上下文管理器包装功能,自动处理stdout的恢复和文件关闭,避免遗忘清理:
import sys from contextlib import contextmanager @contextmanager def tee(filename): original_stdout = sys.stdout log_file = open(filename, 'a', encoding='utf-8') class TeeStream: def write(self, msg): log_file.write(msg) original_stdout.write(msg) original_stdout.flush() log_file.flush() def flush(self): original_stdout.flush() log_file.flush() sys.stdout = TeeStream() try: yield finally: # 退出上下文时自动恢复环境 sys.stdout = original_stdout log_file.close() # 使用示例 with tee('log.txt'): print('进入上下文,所有print都会同时写文件') print('多条信息都能被捕获') # 退出后,print恢复正常输出到控制台 print('这条只会显示在控制台')
内容的提问来源于stack exchange,提问作者Onyz
相关产品推荐
相关产品推荐

