代码之家  ›  专栏  ›  技术社区  ›  Deepak Saini

禁用除在调用函数中完成的打印以外的所有打印

  •  2
  • Deepak Saini  · 技术社区  · 6 年前

    我有一个函数,在这个函数中我从同一个模块或其他模块调用一些函数:

    from __future__ import print_function
    
    def func():
        print("Inside func")
    
    def my_func():
        print("Starting inside my_func ")
        func()
        print("In my_func")
        func()
    

    执行 my_func 输出:

    Starting inside my_func
    Inside func
    In my_func
    Inside func
    

    但我只想看看

    Starting inside my_func
    In my_func
    

    所以,我想禁用所有的打印,除了那些 在函数中 my_func() . 这可能包括对函数的递归调用。所以用堆栈级别做一些事情是行不通的。

    我能想到这么做

    def func():
        print("Inside func")
    
    def my_print(*args):
        print(*args)
    
    def my_func():
        global my_print, print
        my_print("Starting inside my_func ")
        print = functools.partial(print, file=open(os.devnull, 'w'))
        func()
        print = functools.partial(print, file=sys.stdout)
        my_print("In my_func")
        print = functools.partial(print, file=open(os.devnull, 'w'))
        func()
        print = functools.partial(print, file=sys.stdout)
    

    但这涉及到修改函数代码,而且看起来有点黑客。理想情况下,我希望使用一个装饰器来完成这项工作,而不需要修改函数代码。

    最自然的方法是找到不需要的指纹 米奥芬克 把它们输出到 os.devnull 在包装袋里。但我找不到怎么解决这个问题。事先谢谢。

    2 回复  |  直到 6 年前
        1
  •  1
  •   blhsing    6 年前

    您可以将引用保存到 print 变量中的函数 orig_print 超驰 打印 使用不做任何操作的函数,然后在要允许打印的函数上使用修饰符将所有调用重命名为 打印 原版印刷品 用一个 ast.NodeTransformer 子类:

    from __future__ import print_function
    import inspect
    import ast
    from textwrap import dedent
    
    orig_print = print
    print = lambda *args, **kwargs: None
    
    class EnablePrint(ast.NodeTransformer):
        # remove the enable_print decorator from the decorator list so the transformed
        # function won't be re-decorated when executed
        def visit_FunctionDef(self, node):
            node.decorator_list = [
                decorator for decorator in node.decorator_list
                if not isinstance(decorator, ast.Name) or decorator.id != 'enable_print'
            ]
            self.generic_visit(node)
            return node
    
        def visit_Call(self, node):
            if node.func.id == 'print':
                node.func.id = 'orig_print'
            return node
    
    def enable_print(func):
        node = ast.parse(dedent(inspect.getsource(func)))
        EnablePrint().visit(node)
        scope = {}
        exec(compile(node, inspect.getfile(func), 'exec'), func.__globals__, scope)
        return scope[func.__name__]
    

    以便:

    def func():
        print("Inside func")
    
    @enable_print
    def my_func():
        print("Starting inside my_func ")
        func()
        print("In my_func")
        func()
    
    my_func()
    

    输出:

    Starting inside my_func 
    In my_func
    
        2
  •  0
  •   Deepak Saini    6 年前

    @布莱辛给出了一个很好的方法。但最后我用 pprint.pprint 在我的函数中,禁用 print . 这是因为 pprint 使用更多低级别 stream.write("...") 而不是启动 打印 . 代码:

    def disable_prints(f):
        @functools.wraps(f)
        def decorated(*args, **kwargs):
            global print
            # Disable all calls made to print(...) by relacing stdout with devnull
            print = functools.partial(print, file=open(os.devnull, 'w'))
            f_returns = f(*args, **kwargs)
            # Restore back
            print = functools.partial(print, file=sys.stdout)
            return f_returns
        return decorated
    

    以便:

    def func():
        print("Inside func")
    
    @disable_prints
    def my_func():
        pprint("Starting inside my_func")
        func()
        pprint("In my_func")
        func()
    
    my_func()
    

    输出:

    Starting inside my_func 
    In my_func