2

这就是我想要实现的目标


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)

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

4

3 回答 3

7
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 中,这个 contezt 管理器是内置的:

with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
    ...
于 2012-11-06T11:38:08.837 回答
1

InteractiveConsole没有公开任何 API 来设置像对象这样的文件来输出或错误,你需要猴子补丁 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

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

于 2012-11-06T11:51:50.367 回答
0

您可以使用上下文管理器临时重定向标准输出

@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"

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


很容易调整它来重定向和stdouts :stderrcStringIO

@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()
于 2012-11-06T11:38:55.597 回答