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.