临时重定向stdout/stderr
在Python中,有没有办法暂时改变标准输出和错误输出的方向呢?也就是说,只在某个方法执行的时候改变它们的输出?
编辑:
现在的解决方案有个问题(我一开始记得,但后来又忘了),就是它们并不是在“重定向”;而是直接把整个输出流替换掉了。因此,如果某个方法出于某种原因有一个局部副本的变量(比如这个输出流是作为参数传给了其他东西),那就不管用了。
有没有什么解决办法呢?
9 个回答
38
从Python 3.4开始,有一个叫做上下文管理器的东西,具体是contextlib.redirect_stdout
:
from contextlib import redirect_stdout
with open('yourfile.txt', 'w') as f:
with redirect_stdout(f):
# do stuff...
如果你想完全不显示stdout
的内容,可以使用下面的方法:
from contextlib import redirect_stdout
with redirect_stdout(None):
# do stuff...
98
你也可以把重定向的逻辑放在一个上下文管理器里。
import os
import sys
class RedirectStdStreams(object):
def __init__(self, stdout=None, stderr=None):
self._stdout = stdout or sys.stdout
self._stderr = stderr or sys.stderr
def __enter__(self):
self.old_stdout, self.old_stderr = sys.stdout, sys.stderr
self.old_stdout.flush(); self.old_stderr.flush()
sys.stdout, sys.stderr = self._stdout, self._stderr
def __exit__(self, exc_type, exc_value, traceback):
self._stdout.flush(); self._stderr.flush()
sys.stdout = self.old_stdout
sys.stderr = self.old_stderr
if __name__ == '__main__':
devnull = open(os.devnull, 'w')
print('Fubar')
with RedirectStdStreams(stdout=devnull, stderr=devnull):
print("You'll never see me")
print("I'm back!")
25
为了处理某些函数可能把 sys.stdout
流缓存为局部变量的问题,这样在那个函数内部替换全局的 sys.stdout
就不起作用了,你可以在文件描述符的层面上进行重定向(也就是用 sys.stdout.fileno()
)。例如:
from __future__ import print_function
import os
import sys
def some_function_with_cached_sys_stdout(stdout=sys.stdout):
print('cached stdout', file=stdout)
with stdout_redirected(to=os.devnull), merged_stderr_stdout():
print('stdout goes to devnull')
some_function_with_cached_sys_stdout()
print('stderr also goes to stdout that goes to devnull', file=sys.stderr)
print('stdout is back')
some_function_with_cached_sys_stdout()
print('stderr is back', file=sys.stderr)
stdout_redirected()
这个函数可以把所有输出重定向到指定的文件名、文件对象或者文件描述符(在这个例子中是 os.devnull
)。