python - 禁用除在被调用函数中完成的打印之外的所有打印

标签 python printing decorator

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

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)

但这涉及修改功能代码,似乎有点hacky。理想情况下,我希望使用装饰器来执行此操作,而无需修改函数代码。

最自然的方法是找到未在 my_func 中调用的打印并将它们输出到包装器中的 os.devnull。但我找不到该怎么做。提前致谢。

最佳答案

您可以将对 print 函数的引用保存在变量 orig_print 中,并用一个什么都不做的函数覆盖 print,然后使用您希望允许打印的函数上的装饰器将所有对 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

关于python - 禁用除在被调用函数中完成的打印之外的所有打印,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52620202/

相关文章:

python - RC4算法实现过程中出现语法错误

python - Python 中的可定制装饰器

python - 使用 functools.wraps 修饰的函数会引发带有包装器名称的 TypeError。为什么?如何避免?

python - 如何分配给非字符串 "name"或索引的列?

python - 从两个单独的元组开始,如何创建一个非嵌套元组?

python - 尝试使用 Python 3.6 打印字符串中第一次出现的重复字符时出错

api - 是否有全局范围内的按需照片打印 API?

javascript - 使用 Promise 或回调时,装饰器函数返回未定义

python - Scrapy收集数据,但不将其保存到项目中

python - Pandas 数据框 : duplicates based on column and time range