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.