在 Python 的 Spyder 中,将控制台打印到日志文件是不可逆的

Printing the console to a log file is not reversible in Spyder for Python

我正在为 Python 使用 Spyder,有时我想将控制台打印到日志文件中(在输出很长的情况下),有时我只想在控制台上输出.为此,我在 Python 文件中使用了以下结构:

文件开头:

import sys
# specify if the output should be printed on a separate log file or on the console
printLogToFile = False

if printLogToFile == True:
    #Specify output file for the logs
   sys.stdout = open('C:/Users/User 1/logfile.txt', 'w')

文件末尾:

# Close the log file if output is printed on a log file and not on the console
if printLogToFile == True:
    sys.stdout.close()
    sys.stdout = sys.__stdout__

基本上,每当我的布尔变量 printLogToFile 的值为 False 时,所有内容都会按应有的方式打印在控制台上,只要它的值为 True,所有内容都会打印到日志文件中。但是,一旦我 运行 仅一次带有 printLogToFile=True 的文件,这就不能再逆转了。即使变量的值为 False,它仍然会将所有内容打印到日志文件中,而不是打印到控制台上。更奇怪的是,对于与此文件没有任何关联的其他 Python 文件,控制台也不再打印到控制台上。解决此问题的唯一方法是关闭 Spyder 并重新启动它。

您是否知道为什么会发生这种情况以及如何避免这种情况?我会很感激每一条评论。

Spyder 中的控制台是一个 IPython 控制台,而不是一个普通的 Python 控制台,所以我认为 IPython 正在使用 stdout 做一些事情,这会导致你的方法失败。

docs for sys.__stdout__

It can also be used to restore the actual files to known working file objects in case they have been overwritten with a broken object. However, the preferred way to do this is to explicitly save the previous stream before replacing it, and restore the saved object.

换句话说,试试:

if printLogToFile:
    prev_stdout = sys.stdout
    sys.stdout = open('C:/Users/User 1/logfile.txt', 'w')

# code that generates the output goes here

if printLogToFile:
    sys.stdout.close()
    sys.stdout = prev_stdout

作为替代方案,基于 this answer and assuming Python >= 3.7, you can use contextlibwith 语句来选择性地捕获某些代码的输出。这似乎适用于 Spyder 4 和 5:

from contextlib import redirect_stdout, nullcontext

if printLogToFile:
    f = open('myfile.txt', 'w')
    cm = redirect_stdout(f)
else:
    cm = nullcontext()

with cm:
    # code that generates the output goes here

如果您想执行整个 Python 脚本 myscript.py 并捕获它输出的所有内容,可能更容易保持脚本不变并从包装脚本调用它:

# put this in the same folder as myscript.py

from contextlib import redirect_stdout

with redirect_stdout(open('myfile.txt', 'w')):
    import myscript
 

如果您想要比这更灵活的东西,可能是时候开始使用 logging