我有一个无法编辑的函数,它会将结果打印到控制台上。是否可以调用该函数,但在不更改函数内部代码的情况下将控制台输出管道传输到文件中?
例如,我有:
def somefunc(x):
print "Hello World", x**x
def pipeout(func, outfilename)
with open('outfilename', 'w') as fout:
# somehow pipes out the output...
我无法使用logger
,因为我无法编辑somefunc()
。
我尝试过@Aशwiniचhaudhary的解决方案,但我不能。除了第一个输出文件之外,其他文件都是空的,而且它一次又一次地覆盖该文件。:
def redirect_output(file_name):
def decorator(func):
def wrapper(*args):
with open(file_name, 'w') as f:
original_stdout = sys.stdout
sys.stdout = f
func(*args)
sys.stdout = original_stdout
return wrapper
return decorator
def somefunc(x):
print x*x
xs = [1,2,3,4]
for i in xs:
outputfilename = 'results/'+str(i)
somefunc = redirect_output(outputfilename)(somefunc)
somefunc(i)
是的,您可以将sys.stdout
的值设置为另一个具有写访问权限的打开文件。然后您可以使用sys.__stdout__
将其设置回原位
我不久前就有这种需求,并做了一个上下文管理器:
import sys
from StringIO import StringIO
class OutStreamCapture(object):
"""
A context manager to replace stdout and stderr with StringIO objects and
cache all output.
"""
def __init__(self):
self._stdout = None
self._stderr = None
self.stdout = None
self.stderr = None
def __enter__(self):
self._stdout = sys.stdout
self._stderr = sys.stderr
sys.stdout = StringIO()
sys.stderr = StringIO()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""
Restore original values of stderr and stdout.
The captured contents are stored as strings in the stdout and stderr
members.
"""
self.stdout = sys.stdout.getvalue()
self.stderr = sys.stderr.getvalue()
sys.stdout = self._stdout
sys.stderr = self._stderr
你可以这样使用它:
with OutStreamCapture() as osc:
somefunc(x)
然后是osc.stdout
和osc.stderr
,您有两个字符串,其中包含函数分别放入stdout和stderr中的任何内容。
这可以修改为使用任意文件。
请注意这里我在上下文管理器中缓存sys.stdout
的当前值,而不是使用sys.__stdout__
进行恢复。这是因为在我们进入这个上下文的时候,stdout可能已经被重定向了,我们想把它放回原来的样子。
当函数被调用时,您可以使用装饰器将sys.stdout
重定向到文件对象,然后将其恢复到原始STDOUT。
import sys
def redirect_output(file_name):
def decorator(func):
def wrapper(*args):
with open(file_name, 'w') as f:
original_stdout = sys.stdout
sys.stdout = f
func(*args)
sys.stdout = original_stdout
return wrapper
return decorator
@redirect_output('file.txt')
def somefunc(x):
print "Hello World", x**x
somefunc(2)
print 'Hello to console.'
输出:
>>> %run so.py
Hello to console.
>>> !cat file.txt
Hello World 4
更新:
最新代码的工作版本:
for i in xs:
outputfilename = 'results/'+str(i)
new_func = redirect_output(outputfilename)(somefunc)
#or call it directly
#redirect_output(outputfilename)(somefunc)(i)
new_func(i)