0

我有一个无法编辑的功能,它会将结果打印到控制台上。是否可以调用该函数但将控制台输出通过管道传输到文件而不更改函数的内部代码?

例如,我有:

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)
4

2 回答 2

1

您可以使用装饰器在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)
于 2014-04-24T13:50:18.610 回答
1

是的,您可以将 的值设置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.stdoutosc.stderr您有两个字符串,其中包含函数分别放入 stdout 和 stderr 的任何内容。

这可以修改为使用任意文件。

注意,这里我将当前值缓存sys.stdout在上下文管理器中,而不是sys.__stdout__用于恢复。这是因为在我们进入这个上下文时,stdout 可能已经被重定向了,我们想把它恢复到原来的样子。

于 2014-04-24T13:35:07.597 回答