質問

曖昧なタイトルですみません。誰かが提案を持っている場合は、ぜひ教えてください。また、より適切なタグでタグ付けし直してください。

問題

インポートされたクラスのインスタンスがインポーターのスコープ (グローバル、ローカル) 内のものを表示できるようにしたいと考えています。ここで働いている正確なメカニズムはわからないので、言葉で説明するよりも断片を使ったほうがうまく説明できます。

## File 1
def f1():  print "go f1!"

class C1(object):
    def do_eval(self,x):  # maybe this should be do_evil, given what happens
        print "evaling"
        eval(x)
        eval(x,globals(),locals())

次に、反復セッションからこのコードを実行すると、たくさんのコードが表示されます。 NameErrors

## interactive
class C2(object):
    def do_eval(self,x):  # maybe this should be do_evil, given what happens
        print "evaling"
        eval(x)
        eval(x,globals(),locals())

def f2():
    print "go f2!"

from file1 import C1
import file1

C1().do_eval('file1.f1()')
C1().do_eval('f1()')
C1().do_eval('f2()')

file1.C1().do_eval('file1.f1()')
file1.C1().do_eval('f1()')
file1.C1().do_eval('f2()')

C2().do_eval('f2()')
C2().do_eval('file1.f1()')
C2().do_eval('f1()')

この種のタスクに一般的なイディオムやパターンはありますか?私は完全に間違った木に吠えているのでしょうか?

役に立ちましたか?

解決

この例では、関数をオブジェクトとしてメソッドに単純に渡すことができます。 C1:

>>> class C1(object):
>>>    def eval(self, x):
>>>        x()
>>>
>>> def f2(): print "go f2"
>>> c = C1()
>>> c.eval(f2)
go f2

Python では、関数やクラスを他のメソッドに渡し、そこで呼び出したり作成したりできます。

実際にコード文字列を評価したい場合は、Thomas がすでに述べたように、環境を指定する必要があります。

上記のモジュールを少し変更しました。

## File 1
def f1():  print "go f1!"

class C1(object):
    def do_eval(self, x, e_globals = globals(), e_locals = locals()):
        eval(x, e_globals, e_locals)

次に、対話型インタープリターで次のようにします。

>>> def f2():
>>>    print "go f2!"
>>> from file1 import *    # 1
>>> C1().do_eval("f2()")   # 2
NameError: name 'f2' is not defined

>>> C1().do_eval("f2()", globals(), locals()) #3
go f2!
>>> C1().do_eval("f1()", globals(), locals()) #4
go f1!

いくつかの注釈

  1. ここでは、すべてのオブジェクトを次から挿入します。 file1 このモジュールの名前空間に
  2. f2 の名前空間にありません file1, したがって、次の結果が得られます。 NameError
  3. これで環境を明示的に渡し、コードを評価できるようになりました。
  4. f1 インポートしたため、このモジュールの名前空間にあります

編集:の環境を明示的に渡す方法に関するコードサンプルを追加しました。 eval.

他のヒント

関数は、メソッドやクラス本体と同様に、常に定義されているスコープ内で実行されます。これらは別のスコープで実行されることはありません。インポートは単なる代入ステートメントであり、Python のすべては参照であるため、関数、クラス、モジュールはどこにインポートされるかさえ知りません。

次の 2 つのことができます。使用してほしい「環境」を明示的に渡すか、スタックハッカリーを使用して呼び出し元の名前空間にアクセスします。前者は後者ほど実装に依存せず脆弱ではないため、後者よりもはるかに好まれます。

同様のことを試みる string.Template クラスを見てみるとよいでしょう。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top