在Python中关闭函数的stdout而不破坏sys.stdout并恢复每个函数

2024-06-13 07:01:14 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python中,有没有一种方法可以让stdout静音,而不必像下面这样包装函数调用?

原始断码:

from sys import stdout
from copy import copy
save_stdout = copy(stdout)
stdout = open('trash','w')
foo()
stdout = save_stdout

编辑:修正了Alex Martelli的代码

import sys
save_stdout = sys.stdout
sys.stdout = open('trash', 'w')
foo()
sys.stdout = save_stdout

这种方法有效,但似乎效率极低。在那里,是一种更好的方法。有什么想法吗?


Tags: 方法fromimport编辑foosavestdoutsys
3条回答

为了补充其他人已经说过的内容,Python 3.4引入了^{}上下文管理器。它接受要将输出重定向到的文件(-like)对象。

重定向到/dev/null将抑制输出:

In [11]: def f(): print('noise')

In [12]: import os, contextlib

In [13]: with open(os.devnull, 'w') as devnull:
   ....:     with contextlib.redirect_stdout(devnull):
   ....:         f()
   ....:         

In [14]: 

此解决方案可用于装饰:

import os, contextlib

def supress_stdout(func):
    def wrapper(*a, **ka):
        with open(os.devnull, 'w') as devnull:
            with contextlib.redirect_stdout(devnull):
                func(*a, **ka)
    return wrapper

@supress_stdout
def f():
    print('noise')

f() # nothing is printed


在Python 2和Python 3中工作的另一个可能且偶尔有用的解决方案是将/dev/null作为参数传递给f,并使用^{}函数的file参数重定向输出:

In [14]: def f(target): print('noise', file=target)

In [15]: with open(os.devnull, 'w') as devnull:
   ....:     f(target=devnull)
   ....:     

In [16]: 

您甚至可以将target设置为完全可选:

def f(target=sys.stdout):
    # Here goes the function definition

注意,你需要

from __future__ import print_function

在Python 2中。

你为什么认为这是低效的?你测试过吗?顺便说一下,它根本不起作用,因为您正在使用from ... import语句。 替换sys.stdout很好,但不要复制,也不要使用临时文件。改为打开空设备:

import sys
import os

def foo():
    print "abc"

old_stdout = sys.stdout
sys.stdout = open(os.devnull, "w")
try:
    foo()
finally:
    sys.stdout.close()
    sys.stdout = old_stdout

假设foo包含print语句,则在执行此操作时分配stdout变量没有任何效果——这是另一个示例,说明为什么不应该从模块内部的导入内容(正如您在这里所做的),而应该始终将模块作为一个整体(然后使用限定名)。顺便说一下,copy是不相关的。正确的代码片段等价于:

import sys
save_stdout = sys.stdout
sys.stdout = open('trash', 'w')
foo()
sys.stdout = save_stdout

现在当代码正确时,是时候让它更优雅或更快了。例如,可以使用内存中类似文件的对象,而不是文件“trash”:

import sys
import io
save_stdout = sys.stdout
sys.stdout = io.BytesIO()
foo()
sys.stdout = save_stdout

对于优雅来说,a上下文是最好的,例如:

import contextlib
import io
import sys

@contextlib.contextmanager
def nostdout():
    save_stdout = sys.stdout
    sys.stdout = io.BytesIO()
    yield
    sys.stdout = save_stdout

一旦定义了这个上下文,对于任何不需要标准输出的块

with nostdout():
    foo()

更多优化:只需要用一个没有opwrite方法的对象替换sys.stdout。例如:

import contextlib
import sys

class DummyFile(object):
    def write(self, x): pass

@contextlib.contextmanager
def nostdout():
    save_stdout = sys.stdout
    sys.stdout = DummyFile()
    yield
    sys.stdout = save_stdout

使用与前面的nostdout实现相同的方法。我不认为它比这更干净或更快;-)。

相关问题 更多 >