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 の新しいバージョンでは、このコンテスト マネージャーが組み込まれています。

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

コンテキスト マネージャーを使用してstdout を一時的にリダイレクトできます。

@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 に答える