暂时redirectstdout / stderr
是否有可能临时redirectstdout / stderr在Python(即在一个方法的持续时间)?
编辑:
目前的解决scheme(我最初记住但忘记了)的问题是,他们不redirect ; 相反,他们只是完全取代了stream。 因此,如果一个方法由于某种原因(例如,因为stream被作为parameter passing给某个对象)而具有一个variables的本地副本 ,则它将不起作用。
任何解决scheme
为了解决某些函数可能已经将sys.stdout
stream作为局部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