2012-09-04 3 views
13

Python C API関数PyEval_EvalCodeコンパイル済みのPythonコードを実行しましょう。私はPythonコードのブロックを、関数のスコープ内で実行しているかのように実行したいので、グローバル状態に影響を与えないローカル変数の辞書を持っています。C Python:コンテキスト内でのPythonコードの実行

PyEval_EvalCodeあなたは、グローバルとローカル辞書を提供することができますので、これは、行うのに十分に簡単そうです:

PyObject* PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)

私はに実行し、問題はPythonは変数名を検索する方法に関係しています。私はPyEval_EvalCodeで実行することを、次のコードを考えてみましょう:Pythonはfunc内から変数myvarを見つけることができないため

myvar = 300 
def func(): 
    return myvar 

func() 

この単純なコードでは、実際に、エラーが発生します。 myvarは外側のスコープ内のローカルディクショナリにありますが、Pythonはそれを内部スコープ内のローカルディクショナリにコピーしません。これは、次のとおりです。

Pythonが変数名を検索すると、まずlocalsがチェックされ、次にglobalsがチェックされ、最後にbuiltinsがチェックされます。 モジュールスコープでは、localsglobalsがSAMEディクショナリオブジェクトです。したがって、モジュールスコープの文x = 5は、locals辞書にxという辞書を配置します。globals辞書でもあります。今度は、モジュールスコープで定義された関数xは、関数スコープlocals内でxを見つけられません。なぜなら、Pythonはモジュールスコープのローカルを関数スコープのローカルにコピーしないからです。しかし、これは通常、問題ありません。xglobalsにあるためです。

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() 


だから、このすべての結果はモジュールスコープでコードを実行するときに、あなたがしなければならない、ということですグローバルディクショナリとローカルディクショナリがSAMEオブジェクトであることを確認してください。さもなければ、モジュールスコープ関数はモジュールスコープ変数にアクセスすることができません。

私の場合は、グローバル辞書とローカル辞書を同じにすることは望ましくありません。だから私は関数スコープでコードを実行していることをPythonインタプリタに伝える何らかの方法が必要です。これを行うにはいくつかの方法がありますか?私はPyCompileFlagsと追加の引数であるPyEval_EvalCodeExを調べましたが、これを行う方法は見つかりませんでした。

答えて

3

Pythonは実際にスコープ内のローカルをスコープ内のスコープのローカルにコピーしません。 localsのドキュメントは次のように書かれています

フリー・変数は、ファンクション・ブロックではコールされても、クラス・ブロックでは呼び出されません。

ここで、「空き」変数は、ネストされた関数によって閉じられた変数を参照します。それは重要な違いです。あなたが関数内のコードをラップしてコンパイルされたオブジェクトからそれを抽出することができ、そうでない場合

code = """ 
myvar = 300 
def func(): 
    return myvar 

func() 
""" 
d = {} 
eval(compile(code, "<str>", "exec"), d, d) 

状況に最も簡単な修正はglobalslocals同じのdictオブジェクトを渡すだけです:

s = 'def outer():\n ' + '\n '.join(code.strip().split('\n')) 
exec(compile(s, '<str>', 'exec').co_consts[0], {}, {}) 
+0

@ Channel72上記を参照してください。 – ecatmur

関連する問題