You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:19:46