Python C API 関数を使用PyEval_EvalCode
すると、コンパイルされた Python コードを実行できます。Python コードのブロックをfunction のスコープ内で実行しているかのように実行して、グローバル状態に影響を与えないローカル変数の独自の辞書を作成したいと考えています。
グローバル ディクショナリとローカル ディクショナリを提供できるため、これは簡単に実行PyEval_EvalCode
できます。
PyObject* PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
私が遭遇した問題は、Python が変数名を検索する方法に関係しています。で実行する次のコードを検討してくださいPyEval_EvalCode
。
myvar = 300
def func():
return myvar
func()
myvar
Python は内から変数を見つけることができないため、この単純なコードは実際にはエラーを発生させますfunc
。外側のスコープのローカル ディクショナリにあってもmyvar
、Python はそれを内側のスコープのローカル ディクショナリにコピーしません。この理由は次のとおりです。
Python が変数名を検索するときはいつでも、最初に をチェックlocals
し、次に をチェックglobals
し、最後に をチェックしますbuiltins
。モジュール スコープでは、locals
とglobals
は同じディクショナリ オブジェクトです。したがって、x = 5
モジュールスコープのステートメントx
は、locals
辞書でもあるglobals
辞書に配置されます。現在、ルックアップが必要なモジュール スコープで定義された関数は、 function-scope 内でx
は見つかりません。これは、Python がモジュール スコープのローカルを関数スコープのローカルにコピーしないためです。しかし、これは通常は問題にはなりません。x
locals
x
globals
x = 5
def foo():
print(x) # This works because 'x' in globals() == True
Python が外側スコープのローカルを内側スコープのローカルにコピーしているように見えるのは、ネストされた関数のみです。(内部スコープ内で必要な場合にのみ、遅延して行うようにも見えます。)
def foo():
x = 5
def bar():
print(x) # Now 'x' in locals() == True
bar()
したがって、これらすべての結果として、モジュール スコープでコードを実行するときは、グローバル ディクショナリとローカル ディクショナリが同じオブジェクトであることを確認する必要があります。そうしないと、モジュール スコープ関数がモジュール スコープ変数にアクセスできなくなります。
しかし、私の場合、グローバル辞書とローカル辞書を同じにしたくありません。そのため、関数スコープでコードを実行していることを Python インタープリターに伝える何らかの方法が必要です。これを行う方法はありますか?PyCompileFlags
と追加の引数を調べましたが、PyEval_EvalCodeEx
これを行う方法が見つかりません。