Python脚本重定向stdout后sys.stdout.close()引发进程挂起求助
解决Python脚本日志记录与单元格卡住的问题
看起来你遇到的问题根源在于直接替换并关闭sys.stdout,这在Spyder、Jupyter这类交互式环境里会干扰环境的正常输出机制,甚至引发未处理的异常导致单元格无法停止运行。咱们一步步拆解问题并解决:
问题分析
你当前的代码直接把sys.stdout替换成了文件对象,随后又关闭了它,这会带来两个核心问题:
- 关闭
stdout后,后续的print('finish!!!')尝试写入已关闭的流,会触发ValueError: I/O operation on closed file。这个异常在交互式环境里可能不会直接抛出,但会导致进程卡住,无法正常结束单元格运行。 - Spyder和Jupyter的
sys.stdout不是普通的文件,它们有自己的输出捕获逻辑(比如把内容显示在界面的输出框里),强行替换会破坏这个机制,让环境无法识别单元格是否执行完成。
正确的日志记录方案
既然你本来就打算用logging模块,咱们应该用它的原生配置来处理日志输出,既满足记录需求,又不破坏环境的正常运行。下面是两种可行的方案:
方案1:纯Logging配置(推荐)
直接配置logging同时输出到文件和控制台(可选),这样既能完整记录日志,也不影响原有print的输出:
import logging import time # 配置logging:同时写入文件+输出到控制台 logging.basicConfig( level=logging.INFO, # 设置日志级别(INFO及以上都会被记录) format='%(asctime)s - %(levelname)s - %(message)s', # 日志格式(包含时间、级别、内容) handlers=[ logging.FileHandler('my/directory/log.txt'), # 写入指定文件 logging.StreamHandler() # 同时输出到控制台(可选,不需要可以删掉) ] ) # 用logging记录信息 logging.info("here is my log message") # print内容正常输出到控制台(如果保留了StreamHandler,也会被记录到日志) print("here is my print message\n") # 记录单元格运行耗时 start_time = time.time() # --- 这里放你的业务代码 --- time.sleep(2) # 示例:模拟耗时操作 # --- 业务代码结束 --- end_time = time.time() logging.info(f"单元格运行耗时: {end_time - start_time:.2f}秒") print('finish!!!')
方案2:捕获所有Print输出到日志
如果你需要把所有print的内容也写入日志文件,可以临时重定向stdout到logging的流,用完后恢复原stdout,避免影响后续操作:
import logging import sys import time # 配置logging:仅写入文件 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', filename='my/directory/log.txt' ) # 定义一个类,把print的内容转成日志 class PrintToLogger: def write(self, message): if message.strip(): # 过滤空行(避免记录多余的换行) logging.info(message.strip()) def flush(self): pass # 兼容stdout的flush操作,避免报错 # 先保存原stdout,用完要恢复 original_stdout = sys.stdout # 替换stdout为自定义类 sys.stdout = PrintToLogger() # 现在print的内容会被自动记录到日志文件 print("here is my print message\n") # 记录运行耗时 start_time = time.time() # --- 你的业务代码 --- time.sleep(2) # --- 业务代码结束 --- end_time = time.time() print(f"单元格运行耗时: {end_time - start_time:.2f}秒") # 恢复原stdout,避免影响后续输出 sys.stdout = original_stdout # 这个print会输出到控制台,不会被记录到日志 print('finish!!!')
为什么你的代码会卡住?
当你关闭sys.stdout后,后续的print('finish!!!')尝试写入已关闭的流,会触发异常。在Jupyter/Spyder这类交互式环境中,这种异常可能被后台进程捕获,但会打断单元格的正常执行流程,导致环境无法识别"执行完成"的信号,从而一直处于"运行中"状态。
用上面的方案,既能完整记录日志和耗时,又不会破坏交互式环境的正常运行。
内容的提问来源于stack exchange,提问作者Chrissie M.
相关产品推荐
相关产品推荐

