Python 临时重定向stdout/stderr
是否可以在Python中临时重定向stdout/stderr(即在方法期间) 编辑: 当前解决方案的问题(我起初记得,但后来忘记了)是它们没有重定向;相反,它们只是完全替换了流。因此,如果由于任何原因(例如,因为流作为参数传递给某个对象),某个方法具有一个变量的本地副本,则该方法将不起作用Python 临时重定向stdout/stderr,python,redirect,stdout,stderr,Python,Redirect,Stdout,Stderr,是否可以在Python中临时重定向stdout/stderr(即在方法期间) 编辑: 当前解决方案的问题(我起初记得,但后来忘记了)是它们没有重定向;相反,它们只是完全替换了流。因此,如果由于任何原因(例如,因为流作为参数传递给某个对象),某个方法具有一个变量的本地副本,则该方法将不起作用 有什么解决办法吗?我不知道临时重定向是什么意思。但是,您可以像这样重新分配流并将其重置回来 temp = sys.stdout sys.stdout = sys.stderr sys.stderr = tem
有什么解决办法吗?我不知道临时重定向是什么意思。但是,您可以像这样重新分配流并将其重置回来
temp = sys.stdout
sys.stdout = sys.stderr
sys.stderr = temp
也可以像这样在打印stmts中写入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
或者,如果您不想修改fun
的源代码,请直接将其作为
redirect_stderr_stdout(some_logging_stream, the_console)(fun)
但请注意,这不是线程安全的。您也可以将重定向逻辑放在contextmanager中
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!")
这是一个我觉得有用的上下文管理器。它的好处是,您可以将它与
with
语句一起使用,它还可以处理子进程的重定向
导入上下文库
@contextlib.contextmanager
def stdchannel_已重定向(stdchannel,dest_文件名):
"""
用于临时重定向stdout或stderr的上下文管理器
例如。:
重定向stdchannel_时(sys.stderr,os.devnull):
...
"""
尝试:
oldstdchannel=os.dup(stdchannel.fileno())
dest_文件=打开(dest_文件名'w')
os.dup2(dest_file.fileno(),stdchannel.fileno())
产量
最后:
如果oldstdchannel不是None:
os.dup2(oldstdchannel,stdcchannel.fileno())
如果dest_文件不是None:
dest_file.close()文件
我为什么创建这个的背景是。向我们展示了一种更好的方法[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
使用块后,将重置sys.stdout
[1] :要解决某些函数可能已将
sys.stdout
流缓存为局部变量,因此替换全局sys.stdout
在该函数内不起作用的问题,可以在文件描述符级别(sys.stdout.fileno()
)重定向,例如:
将sys.stdout.fileno()的所有输出重定向到给定的文件名、文件对象或文件描述符(os.devnull
)
.我们将在python3中使用和函数的
PHP
语法,并将输入重定向到文件中
输出存储在文件中,也可以使用任何类型的流
from functools import partial
output_buffer = None
print_orig = print
def ob_start(fname="print.txt"):
global print
global output_buffer
print = partial(print_orig, file=output_buffer)
output_buffer = open(fname, 'w')
def ob_end():
global output_buffer
close(output_buffer)
print = print_orig
def ob_get_contents(fname="print.txt"):
return open(fname, 'r').read()
用法:
print ("Hi John")
ob_start()
print ("Hi John")
ob_end()
print (ob_get_contents().replace("Hi", "Bye"))
将打印
嗨,约翰
再见,约翰
从python 3.4开始,有一个上下文管理器: 要使标准输出完全静音,请执行以下操作:
from contextlib import redirect_stdout
with redirect_stdout(None):
# do stuff...
看和看。在Python3.5中是新的。我想我可以包装一个
try finally
;看起来会管用的,虽然没有我想要的那么漂亮。感谢+1此示例适用于我们这些坚持使用python 2.2的人。谢谢你不需要临时工。sys.\uu stderr\uuuuuuu始终是正确的对象。+1对于我在Python中看到的这个问题的最干净、最简单的解决方案,您不需要temp
变量。您可以调用sys.stdout,sys.stderr=sys.stderr,sys.stdout+1似乎就是我需要的。只是好奇,你为什么要做一个except:raise
。顺便说一句,我重写了整件事。;我第一次总是错误地理解decorators中的嵌套级别,但现在它实际上可以工作了。你知道,我注意到一个问题:如果程序缓存了流对象(例如,将它们作为参数传递给接受流的函数),该怎么办?那么这就行不通了有没有办法重定向流本身,而不是用新的流替换它们?@Mehrdad:然后你可以做一些低级的文件描述符魔术,或者甚至在执行所需代码之前,在子级中分叉并重定向流,并通过管道返回结果。恐怕这里没有什么灵丹妙药。将return wrap(f)改为return wrap预定向stdout/stderr并不少见(或者至少并非闻所未闻)——这里的答案很好地解释了这个过程。@TokenMacGuy:虽然你永远不应该编写将输出连接到stderr
或stdout
的库代码,您不能总是避免使用这种代码。@Mehrdad在导入第三方代码之前,请尝试替换sys.\u stdout\uuuumodules@Rob:我想你错过了我标题中的第二个字。:-)@梅尔达德:不。将代码早期的sys.\uu stdout\uuuu替换为您自己的流式对象(即实现.write()
)。对sys.stdout的所有引用都指向它。将其代理到可变流,默认为标准输出。然后,您应该能够随意切换代理流。我没有试过这个;我想得很清楚,-1--带有的将不会恢复初始的sys.stdout
。如果您试图在使用
块的之后打印某些内容,您将收到一个值错误:对关闭的文件执行I/O操作。
。您应该用
删除第二个,并将一个sys.stdout=sys.\uuu stdout\uuuu
放在第一个块的末尾。此答案将替换sys.stdout
,sys.stderr
,而不是在编辑的问题版本中按OP要求重定向它们。请参阅。@RobCowie:Style问题:您之所以将self.\u stdout
“受保护”(在Python意义上)与self.\u stdout
“私有”(在Python意义上)进行比较,是有原因的吗?我似乎从来没有创建过私有的双下划线属性。我还没有找到一种情况来证明这一点。@kevinarpe-在x.\u-bar
和x.\u-bar
之间没有什么区别,只是x.\u-bar
更难理解,因为名称被弄错了。事实上,这并不能使这个变量
from contextlib import redirect_stdout
with open('yourfile.txt', 'w') as f:
with redirect_stdout(f):
# do stuff...
from contextlib import redirect_stdout
with redirect_stdout(None):
# do stuff...