如何在更改标准输出时使用包装器覆盖打印功能

How to override the print function with wrapper while changing stdout

我正在尝试构建一个具有以下目标的包装器:

  1. 捕捉任何函数的打印以保存它们供以后使用(让我们 return 暂时列出一个列表)
  2. 要在包装函数中也覆盖打印以添加时间戳以获得更好的日志记录和更多信息(我不想 log.info() 因为这意味着要更改包装函数中的打印,如果我稍后想在包装器中这样做,我将失去时间的精度)

目标始终是不更改包装函数中的任何内容,而不只是包装它们

到目前为止,这是我的代码:

def my_decorator(func):
    def wrapped_func(*args,**kwargs):
         return func("Here we add a timestamp",*args,**kwargs)
    return wrapped_func

def list_prints_to_logs(list_prints):
    for log in list_prints:
        logger.info(log)

def my_handler(func):
    def wrapper(*args,**kwargs):

        print('this is BEFORE the function')
        old_print = print                        
        print = my_decorator(print)

        ### catching the outputs of the function
        old_stdout = sys.stdout
        sys.stdout = tempstdout = StringIO()
        results = func(*args,**kwargs)  # THE ERROR STARTS IN HERE AFTER ENTERING THIS FUNCTION
        sys.stdout = old_stdout


        print('this is AFTER the function')
        prints_in_function = tempstdout.getvalue().splitlines()
        list_prints_to_logs(prints_in_function)  

        #trying to return the print like it was before
        print = old_print 
        print(*prints_in_function, sep='\n')        

        return results
    return wrapper


@my_handler
def my_func(arg=1,kwarg='yes'):

    print('this is inside the Function')
    print('this is second print in the function')


my_func()

而 return 给我的错误是:

UnboundLocalError: local variable 'print' referenced before assignment

错误的行是从打印里面开始的my_func

我在如何临时覆盖一个函数方面遇到了困难,并在下一次调用中坚持这个覆盖,

UnboundLocalError 是因为你分配了局部变量但在分配之前使用了它。
通常当你在函数中使用赋值语句时,它会绑定一个局部变量。
如果你想绑定全局变量,你应该在赋值之前使用global语句。

def my_handler(func):
    def wrapper(*args,**kwargs):
        global print
        ...
        print = my_decorator(print)
        ...
        print = old_print 
        print(*prints_in_function, sep='\n')        

        return results
    return wrapper

但是,这个装饰器不会影响到模块外部。如果你想影响包含其他模块,你应该重新绑定builtins.print

import builtins
def my_handle(func):
    def wrapper(*args,**kwargs):
        ...
        builtins.print = my_decorator(print)
        ...
        builtins.print = old_print
        ...
    return wrapper