How to print the console to a text file AFTER the

2019-05-09 12:43发布

问题:

I have a program that outputs many calculations and results to the console through the print statement. I want to write some code to export (or save) all the contents of the console to a simple text file.

I searched StackOverflow and other sites but I found some methods to redirect the print statement to print to a file directly, but I want the program to work normally, to display outputs to the console, then to save its contents AFTER all operations of the program done.

I am using PyCharm with Python2.7 if it matters

回答1:

Ok, so normally to get it done, you have to rewrite python print built-in function. But... There is ipython, which provides some hooks.

First you need to have ipython installed:

#bash
sudo pip install ipython

(I'm using sudo to simple locate then folder I need to reach, read further)

After ipython installation you'll have ipython extensions folder available, so get to it:

#bash
cd ~/.ipython/extensions/

and create there let's say a file called print_to_file.py, here is its content:

#python
class PrintWatcher(object):
    def __init__(self, ip):
        self.shell = ip

    def post_execute(self):
        with open('/home/turkus/shell.txt', 'a+') as f:
            in_len = len(self.shell.user_ns['In'])
            i = in_len - 1

            in_ = self.shell.user_ns['In'][i]
            out = self.shell.user_ns['Out'].get(i, '')
            # you can edit this line if you want different input in shell.txt
            f.write('{}\n{}\n'.format(in_, out))


def load_ipython_extension(ip):
    pw = PrintWatcher(ip)
    ip.events.register('post_run_cell', pw.post_execute)

After saving a file just run:

#bash
ipython profile create 

# you will get something like that:
[ProfileCreate] Generating default config file: u'/home/turkus/.ipython/profile_default/ipython_config.py'

Now get back to setting up our hook. We must open ipython_config.py created under path above and put there some magic (there is a lot of stuff there, so go to the end of file):

# some commented lines here
c = get_config()
c.InteractiveShellApp.extensions = [
    'print_to_file'
]

After saving it, you can run ipython and write your code. Every your input will be written in a file under path you provided above, in my case it was:

/home/turkus/shell.txt

Notes

You can avoid loading your extension every time ipython fires up, by just delete 'print_to_file' from c.InteractiveShellApp.extensions list in ipython_config.py. But remember that you can load it anytime you need, just by typing in ipython console:

➜  ~ ipython
Python 2.7.12 (default, Jul  1 2016, 15:12:24) 
Type "copyright", "credits" or "license" for more information.

IPython 4.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: %load_ext print_to_file

Any change in print_to_file.py is being reflected in open ipython shell after using %reload_ext print_to_file command, so you don't have to exit from and fire up it again.



回答2:

I am unsure how you could receive the contents of a console for any editor however this can be achieved quite simply by replacing your print() statements with .write

class Writer(object):
    def __init__(self, out_file, overwrite=False):
        self.file_name = out_file
        self.overwrite = overwrite
        self.history = []

    def write(self, statement):
        self.history.append(statement)
        print statement

    def close(self):
        if self.overwrite:
            self.out_file = open(self.file_name, 'wb')
        else:
            self.out_file = open(self.file_name, 'ab')
        for x in self.history:
            self.out_file.write(x+'/n')
        self.out_file.close()
        self.history = []

p = Writer('my_output_file.txt')
p.write('my string to print and save!') 
p.close() #close the writer to save the contents to a file before exiting


回答3:

After I know understood your question I think you search the tee command

python your_program | tee output.txt

This will show you the output both, in the console and in output.txt

PS: Since you did not answer to my comment which OS you use I assumed that you use either Linux or MACOS. Should work on both. I don't know how to do this on windows...



回答4:

You could override the print function which will still be accessible through the builtins module

import builtins

f = open("logs.txt", "w")

def print(*args, sep=' ', end='\n', **kwargs):
    builtins.print(*args, sep=sep, end=end, **kwargs)
    f.write(sep.join(*args) + end)

EDIT: A similar solution for Python 2

from __future__ import print_function

class Print:

    def __init__(self, print_function, filename='test', mode='w'):
        self.print_function = print_function
        self.file = open(filename, 'w')

    def __call__(self, *args, **kwargs):
        self.print_function(*args, **kwargs)
        kwargs['file'] = self.file
        self.print_function(*args, **kwargs)

print = Print(print, 'logs.txt')

This creates a print function that you use exactly as the function you import from __future__.
To close the file when everything is done you have to run:

print.file.close()


回答5:

Maybe you should create a variable that will log the outputs and then put it into a file.

For ex:

print statement
logger += statement+"\n" #a new line char so each statement is on a new line

with open('file.txt', 'a') as f:
   f.write(statement)


回答6:

With all thanks and respect to all who contributed to this question. I have finally found a solution to this problem with minimal modifications to my original code. The solution is provided by the member @Status and here is its link .

Although I searched a lot before posting my question, but the answers of the respected members enlightened my mind to a precise search especially the contributions of @turkus, who performs an exceptional work, and @Glostas who opened my eyes to the "tee" which guided me to find the solution I posted (although it does not contain "tee").

The solution, as of the mentioned post with slight modifications:

1- Put the following Class in the program:

class Logger(object):
"""
Lumberjack class - duplicates sys.stdout to a log file and it's okay
source: https://stackoverflow.com/a/24583265/5820024
"""
def __init__(self, filename="Red.Wood", mode="a", buff=0):
    self.stdout = sys.stdout
    self.file = open(filename, mode, buff)
    sys.stdout = self

def __del__(self):
    self.close()

def __enter__(self):
    pass

def __exit__(self, *args):
    pass

def write(self, message):
    self.stdout.write(message)
    self.file.write(message)

def flush(self):
    self.stdout.flush()
    self.file.flush()
    os.fsync(self.file.fileno())

def close(self):
    if self.stdout != None:
        sys.stdout = self.stdout
        self.stdout = None

    if self.file != None:
        self.file.close()
        self.file = None

2- At the beginning of the program, before any print statements, put this line:

my_console = Logger('my_console_file.txt')  # you can change the file's name

3- At the end of the program, after all of the print statements, put this line:

my_console.close()

I tested this, and It works perfectly, and finally I have a clone of the console's output after the program ends.

With best regards to everybody, and Many thanks to all contributors.



回答7:

There is a very obvious but not very elegant solution.

instead of:

print statement 1
calculation
print statement 2

you can make something like

sexport =''
calculation
print statement 1
sexport += statement1 + "\n"
calculaztion
print statement 2
sexport += statement 2 

finally just save sexport to a file