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

Python 禁用除在被调用函数中完成的打印之外的所有打印,python,printing,decorator,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_fun

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

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)
但这涉及到修改函数代码,而且似乎有点不成熟。理想情况下,我希望使用decorator实现这一点,而不需要修改函数代码


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

您可以将对
print
函数的引用保存在变量
orig\u print
中,并使用不执行任何操作的函数覆盖
print
,然后在要允许打印的函数上使用修饰符,使用
ast.NodeTransformer
子类将对
print
的所有调用重命名为
orig\u print

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()
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

@布莱辛给出了一个很好的方法。但我最终在函数中使用
pprint.pprint
解决了问题,并禁用了
print
的输出。这是因为
pprint
使用了更低级的
流。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")

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

my_func()
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

我的回答能解决你的问题吗?如果是,你能接受这个答案吗?如果没有,请让我知道这个答案没有解决哪些问题。嗨,谢谢。它起作用了。如果有更多的人回答,我会等的。没问题。如果您觉得新答案更好,您随时可以接受。此答案实际上没有回答问题,因为它实际上没有在装饰功能中使用
print
,其中
print
仍处于禁用状态,这不符合您的目标“我想禁用除函数
my_func()
“。此外,在函数调用期间全局重写
print
不是线程安全的,因此,如果调用修饰函数的线程需要同时运行,则当其他线程不在此函数内时,当此函数内的线程需要
print
禁用时,将由其他线程重新启用打印。此外,
pprint
的行为与
print
截然不同。与
print
不同,
pprint
始终打印给定对象的
\uuu repr\uuuu
方法的输出,因此
pprint('hi')
将输出
'hi'
,而不是
hi
,因此不是
print
生成用户友好输出的好替代品。要点如下。谢谢离开ans,这似乎更容易理解。