在Python中将python函数的输出从STDOUT重定向到变量

时间:2012-11-06 11:27:58

标签: python io-redirection

这就是我想要实现的目标


def fun():
    runner = InteractiveConsole()
    while(True):
        code = raw_input()
        code.rstrip('\n')
        # I want to achieve the following
        # By default the output and error of the 'code' is sent to STDOUT and STDERR
        # I want to obtain the output in two variables out and err
        out,err = runner.push(code)

到目前为止我所看到的所有解决方案都使用任一管道来发出单独的脚本执行命令(在我的情况下这是不可能的)。我可以通过其他任何方式实现这一目标吗?

3 个答案:

答案 0 :(得分:6)

import StringIO, sys
from contextlib import contextmanager

@contextmanager
def redirected(out=sys.stdout, err=sys.stderr):
    saved = sys.stdout, sys.stderr
    sys.stdout, sys.stderr = out, err
    try:
        yield
    finally:
        sys.stdout, sys.stderr = saved


def fun():
    runner = InteractiveConsole()
    while True:
        out = StringIO.StringIO()
        err = StringIO.StringIO()
        with redirected(out=out, err=err):
            out.flush()
            err.flush()
            code = raw_input()
            code.rstrip('\n')
            # I want to achieve the following
            # By default the output and error of the 'code' is sent to STDOUT and STDERR
            # I want to obtain the output in two variables out and err
            runner.push(code)
            output = out.getvalue()
        print output

在较新版本的python中,此上下文管理器内置于:

with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
    ...

答案 1 :(得分:1)

InteractiveConsole没有公开用于设置输出或错误的对象等文件的API,您需要monkey patch sys.stdoutsys.stderr。与猴子修补一样,要注意副作用可能是什么。在这种情况下,您将使用自己的实现替换全局stdin和stdout文件对象,这可能会吞噬非预期的输出(特别是如果您使用任何线程)。

使用类似的东西来“输出”输出会更安全一些:

import sys
import StringIO


class TeeBuffer(object):

    def __init__(self, real):
        self.real = real
        self.buf = StringIO.StringIO()

    def write(self, val):
        self.real.write(val)
        self.buf.write(val)


def fun():
    runner = InteractiveConsole()

    out = TeeBuffer(sys.stdout)
    err = TeeBuffer(sys.stderr)

    sys.stdout = out
    sys.stderr = err

    while(True):
        code = raw_input()
        code.rstrip('\n')

        out, err = runner.push(code)
        outstr = out.buf.getvalue()
        errstr = err.buf.getvalue()

    sys.stdout = out.real
    sys.stderr = err.real

然后您的用户仍然可以看到输出,而无需担心每次运行时将其打印回正确的位置。

答案 2 :(得分:0)

您可以使用上下文管理器redirect stdout temporarily

@contextmanager
def stdout_redirected(new_stdout):
    save_stdout = sys.stdout
    sys.stdout = new_stdout
    try:
        yield None
    finally:
        sys.stdout = save_stdout
     

使用如下:

with opened(filename, "w") as f:
    with stdout_redirected(f):
        print "Hello world"
     

当然,这不是线程安全的,但也没有手动进行同样的舞蹈。在单线程程序中(例如,在脚本中),它是一种流行的做事方式。


可以轻松调整此选项,将stdoutstderr重定向到cStringIO

@contextmanager
def out_redirected():
    save_stdout = sys.stdout
    save_stderr = sys.stderr
    sys.stdout = cStringIO.String()
    sys.stderr = cStringIO.String()
    try:
        yield sys.stdout, sys.stderr
    finally:
        sys.stdout = save_stdout
        sys.stderr = save_stderr

您将其用作

with out_redirected() as out, err:
    runner.push(code)
    out.seek(0)
    print out.read()