2017-03-01 9 views
-1

インタープリタで実行できるにもかかわらず、関数を使っていくつかのものをインポートする際に問題があります。インタプリタを使用しても成功したにもかかわらず、関数を使用してexecを動的にインポートできない

私のスクリプトと同じディレクトリにあるフォルダAにinput.pyというファイルがあるとします。このファイルでは、変数 'B'を定義します。

B = 5 

私は通訳に行くとき、次のコマンドは私にB

>>> import sys 
>>> sys.path.append('A') 
>>> exec('from inputs import *') 
>>> print(B) 

の正しい値を与えるしかし、私は別々のファイルにそのコードを移動した場合、「test.py」を言う:

import sys 

def import_stuff(import_dir): 
    sys.path.append(import_dir) 
    exec('from inputs import *') 
    print(B) 

そして、そのようインタプリタからそれを呼び出す:

>>> import test 
>>> test.import_stuff('A') 

NameErrorが発生し、Bが見つかりません。どうしたの?

+0

あなたは 'input'の代わりに' inputs'をミスタイプしました。 – mFoxRU

+0

ありがとうございます。しかし、これはスタックオーバーフローのコードを転送する際に作成された誤植で、私のオリジナルコードには存在しません。質問が修正されました。 – Aozturk

+0

あなたのファイルは 'input.py'ではなく' inputs.py'という名前ですか? – mFoxRU

答えて

0

関数のローカル変数は、グローバル変数とオブジェクト属性(名前を値にマップするために辞書を使用する)とは異なる方法で扱われます。

関数が定義されると、Pythonコンパイラはそのコードを調べ、どのローカル変数名が使用されているかを記録し、それぞれの "スロット"を指定します。関数が呼び出されると、スロットはフレームオブジェクト内のメモリの一部を参照します。ローカル変数の代入とルックアップは、名前ではなく番号でスロットにアクセスします。これにより、ローカル変数のルックアップが、グローバル変数や属性のルックアップよりも格段に高速になります(スロットのインデックス付けはdictルックアップよりもはるかに高速です)。

execを使用してローカル変数を作成しようとすると、スロットをバイパスします。コンパイラは、どの変数がexecのコードに作成されるのかわからないので、割り当てられたスロットはありません。これはまた、Python 3が関数内でfrom module import *を使用できない理由です。インポートされる名前は関数のコンパイル時には認識されません(実行され、インポートされたモジュールがロードされたときのみ)名前のスロットを設定します。

execのコードに割り当てられると予想される名前のローカル変数を別々に初期化しても、それでも機能しません。 execのdコードは、関数内から実行されていることを知らず、辞書に変数を書き込むことを常に望んでいます(スロットを機能させないでください)。関数の代入をキャッチしない(グローバル変数にならない)ローカル名前空間辞書があるが、関数locals()を使ってそれを使用するのは非常に不安定である。 locals()を呼び出すたびに、スロットに格納されているすべてのローカル変数の値が辞書にコピーされますが、他の方向へのコピーは行われません(locals()から返された辞書を変更しても、通常の方法でアクセスしました)。

これは、私がこの問題を回避する最善の方法だと私に思います。 execを現在の名前空間に変更するのではなく、明示的に辞書を渡して名前空間として使用する必要があります。

def import_stuff(import_dir): 
    sys.path.append(import_dir) 
    namespace = {}       # create a namespace dict 
    exec('from inputs import *', namespace) # pass it to exec 
    print(namespace["B"])     # read the results from the namespace 
関連する問題