简体   繁体   中英

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

I am using Spyder for Python and sometime I would like to print the console into a log file (in cases where the output is quite long) and sometimes I just want to have the output at the console. For this purpose I use the following construction in my Python files:

In the beginning of the file:

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')

At the end of the file:

# 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__

Basically, whenever my boolean variable printLogToFile has the value False then everything is printed on the console as it should and whenever it has the value True everything is printed into the logfile. However, once I run just once the file with printLogToFile=True this can't be reversed any longer. Even when the variable has the value False it still prints everything into the log file and not onto the console. What is even more strange is that also for other Python files, that do not have any connection to this file, the console is not printed any longer onto the console. The only way to solve this problem is to close Spyder and restart it again.

Do you have any idea why this is happening and how to avoid this? I'd appreciate every comment.

The console in Spyder is an IPython console, not a plain Python console, so I think IPython is doing something with stdout that causes your approach to fail.

The docs for sys.__stdout__ say

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.

In other words, try:

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

As an alternative, based on this answer and this answer assuming Python >= 3.7, you can use contextlib and a with statement to selectively capture the output of some of your code. This seems to work for me in Spyder 4 and 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

If you want to execute the whole of your Python script myscript.py and capture everything it outputs, it's probably easier to leave your script unmodified and call it from a wrapper script:

# put this in the same folder as myscript.py

from contextlib import redirect_stdout

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

If you want anything more flexible than that, it's probably time to start using logging .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM