0

次のようなコードがあります。

    try:
        c = compile(s, COMPILE_STRING_FN, "single")
    except Exception as e:
        answer = (idx, "compile-exception", (e.__class__.__name__, str(e)))
    else:
        try:
            ret = eval(c, globals, locals)
        except Exception as e:
            answer = (idx, "eval-exception", (e.__class__.__name__, str(e)))
        else:
            if ret is not None:
                try:
                    ret = str(ret)
                except Exception as e:
                    ret = "<str-cast exception: %s: %s>" % (e.__class__.__name__, str(e))
            answer = (idx, "return", ret)

これは期待どおりに機能しません。なぜならretNone値が存在する場合は代わりに出力されるからです。これは私が望んでいるものではありません - 私はそれを入れたいですret

それは"single"私にとって正しいコンパイルモードではないようです。また、s = "def f(): return 42"動作しません。

ただし、"eval"単一の式だけでなく、任意のコマンドをサポートしたいからでもありません。

また、 mode"exec"を使用すると、戻り値も取得できません。

それで、解決策は何でしょうか?


アップストリームの提案:出力する代わりに値を返すための単一実行のコンパイルフラグ


ユース ケース: Python リモート シェル。いつでもアプリケーションにアタッチできるように、これを実装しました。サーバーsocketcontrolモジュールクライアントの対話型シェルの実装

4

1 に答える 1

0

の代わりにcompile(s, COMPILE_STRING_FN, "single")、次の関数を使用できます。

def interactive_py_compile(source, filename="<interactive>"):
    c = compile(source, filename, "single")

    # we expect this at the end:
    #   PRINT_EXPR     
    #   LOAD_CONST
    #   RETURN_VALUE    
    import dis
    if ord(c.co_code[-5]) != dis.opmap["PRINT_EXPR"]:
        return c
    assert ord(c.co_code[-4]) == dis.opmap["LOAD_CONST"]
    assert ord(c.co_code[-1]) == dis.opmap["RETURN_VALUE"]

    code = c.co_code[:-5]
    code += chr(dis.opmap["RETURN_VALUE"])

    CodeArgs = [
        "argcount", "nlocals", "stacksize", "flags", "code",
        "consts", "names", "varnames", "filename", "name",
        "firstlineno", "lnotab", "freevars", "cellvars"]
    c_dict = dict([(arg, getattr(c, "co_" + arg)) for arg in CodeArgs])
    c_dict["code"] = code

    import types
    c = types.CodeType(*[c_dict[arg] for arg in CodeArgs])
    return c
于 2013-02-25T04:16:40.193 に答える