暂时redirectstdout / stderr

是否有可能临时redirectstdout / stderr在Python(即在一个方法的持续时间)?

编辑:

目前的解决scheme(我最初记住但忘记了)的问题是,他们不redirect ; 相反,他们只是完全取代了stream。 因此,如果一个方法由于某种原因(例如,因为stream被作为parameter passing给某个对象)而具有一个variables的本地副本 ,则它将不起作用。

任何解决scheme

为了解决某些函数可能已经将sys.stdoutstream作为局部variablescaching的问题,因此replace全局的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()sys.stdout.fileno()所有输出redirect到给定的文件名,文件对象或文件描述符(在本例中为os.devnull )。

这里定义了stdout_redirected()merged_stderr_stdout()

您也可以将redirect逻辑放在上下文pipe理器中。

 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!") 

我不确定临时redirect是什么意思。 但是,您可以重新分配这样的stream并将其重置。

 temp = sys.stdout sys.stdout = sys.stderr sys.stderr = temp 

也可以像这样在打印文件中写入sys.stderr。

  print >> sys.stderr, "Error in atexit._run_exitfuncs:" 

定期打印将标准输出。

这是可能的装饰,如下所示:

 import sys def redirect_stderr_stdout(stderr=sys.stderr, stdout=sys.stdout): def wrap(f): def newf(*args, **kwargs): old_stderr, old_stdout = sys.stderr, sys.stdout sys.stderr = stderr sys.stdout = stdout try: return f(*args, **kwargs) finally: sys.stderr, sys.stdout = old_stderr, old_stdout return newf return wrap 

用于:

 @redirect_stderr_stdout(some_logging_stream, the_console): def fun(...): # whatever 

或者,如果您不想修改源代码,请直接调用它

 redirect_stderr_stdout(some_logging_stream, the_console)(fun) 

但请注意,这不是线程安全的。

这是我发现有用的上下文pipe理器。 关于这一点的好处是你可以和with语句一起with ,也可以处理subprocess的redirect。

 import contextlib @contextlib.contextmanager def stdchannel_redirected(stdchannel, dest_filename): """ A context manager to temporarily redirect stdout or stderr eg: with stdchannel_redirected(sys.stderr, os.devnull): ... """ try: oldstdchannel = os.dup(stdchannel.fileno()) dest_file = open(dest_filename, 'w') os.dup2(dest_file.fileno(), stdchannel.fileno()) yield finally: if oldstdchannel is not None: os.dup2(oldstdchannel, stdchannel.fileno()) if dest_file is not None: dest_file.close() 

为什么我创build这个背景是在这篇博客文章 。

Raymond Hettinger向我们展示了一个更好的方法[1]:

 import sys with open(filepath + filename, "w") as f: #replace filepath & filename with f as sys.stdout: print("print this to file") #will be written to filename & -path 

在with block之后,sys.stdout将被重置

[1]: http : //www.youtube.com/watch?v=OSGv2VnC0go&list=PLQZM27HgcgT-6D0w6arhnGdSHDcSmQ8r3