问题
I am wondering if the build-in function print
could be overridden so that the following statement will write to the console and a file at the same time.
print("test0","test1","test2",sep='\n')
Also, may I know if it is possible to modify the source code of the build-in print
function?
回答1:
You can create a class with a write
method and inside of that method you can print
both stdout
as well as write
to the file.
import sys
class A(object):
def __init__(self, f):
self.f = open(f, 'w')
def __enter__(self):
return self # return instance of A which is assign to `f`.
def write(self, text):
sys.stdout.write(text) # print to the shell
self.f.write(text) # write in the file
def __exit__(self, *args):
self.f.close()
return True
with A('foo.txt') as f:
print("test0","test1","test4",sep='\n', file=f) #`file = f` calls `write` method
回答2:
Use a decorator. Simplified example:
def my_decorator(func):
def wrapped_func(*args,**kwargs):
return func("I've been decorated!",*args,**kwargs)
return wrapped_func
print = my_decorator(print)
Test:
print("TESTING") #I've been decorated! TESTING
So to print to a file at the same time you might do:
def super_print(filename):
'''filename is the file where output will be written'''
def wrap(func):
'''func is the function you are "overriding", i.e. wrapping'''
def wrapped_func(*args,**kwargs):
'''*args and **kwargs are the arguments supplied
to the overridden function'''
#use with statement to open, write to, and close the file safely
with open(filename,'a') as outputfile:
outputfile.write(*args,**kwargs)
#now original function executed with its arguments as normal
return func(*args,**kwargs)
return wrapped_func
return wrap
print = super_print('output.txt')(print)
If you compare this to the example above, you'll see there is an additional closure in this situation (i.e., return wrapped_func
AND return wrap
instead of just return wrapped_func
). This second closure allows us to send an additional argument (filename
) into the wrapper/decorator function.
The syntax of this last line looks a little weird, but this is the correct way. The call to super_print('output.txt')
returns an object which is then given the print
function object as an additional argument. This whole thing works via closures; research them if you aren't up to speed.
Then:
print('test')
test
will be written to console output and to output.txt.
回答3:
print
function uses sys.stdout
unless the explicit file
parameter is given.
You could redirect sys.stdout
to a file-like object that writes to a console and a file at the same time:
#!/usr/bin/env python3
import sys
from contextlib import redirect_stdout
class TeeFile: # write to multiple files at once
def __init__(self, *files):
self.files = files
def write(self, data):
for file in self.files:
file.write(data)
def flush(self):
for file in self.files:
file.flush()
with open('log', 'a') as log, redirect_stdout(TeeFile(log, sys.stdout)):
print("test0", "test1", "test2", sep='\n')
redirect_stdout
is introduced in Python 3.4 but it is easy to implement it on earlier versions.
You could replace builtins.print
function if you want to replace the print
function globally.
Consider whether logging
module provides a better solution than print
function in your case.
回答4:
It's probably a little late for this answer, but I've created a package (https://github.com/phohenecker/stream-to-logger) that provides exactly what you are looking for, namely redirecting stdout+stderr to a file (in addition to the usual printing to the screen).
It's super-easy, you just have to add two lines to your code:
import streamtologger
streamtologger.redirect(target="./all-output.log")
You can install the package with pip:
pip install git+https://github.com/phohenecker/stream-to-logger
来源:https://stackoverflow.com/questions/27621655/how-to-overload-print-function-to-expand-its-functionality