3

次のようなスクリプトがあります

from mapper import Mapper

class A(object):
    def foo(self):
        print "world"

a = A()
a.foo()
Mapper['test']()

ファイルでMapper定義されているmapper.py:

Mapper = {'test': a.foo}

mapper.pyでは定義されていないが元のコードで定義されているオブジェクトを参照する関数呼び出しを定義したい。ただし、上記のコードではエラーが発生します

NameError: name 'a' is not defined

aそれ自体は定義されていないので、これは意味がありmapper.pyます。globalsただし、メインコード自体、または何かを使用して、コードが名前解決を行うようにコードを変更することは可能ですか?

この問題を解決するには、実装をmapper.pyテキストとして指定evalし、メイン コードで使用することができますが、eval.

追加情報:

  • 関数の完全な定義は、mapper.py
  • インスタンスが何であるか、またはどのクラスからインスタンス化されているかは事前にわかりませんa
4

2 に答える 2

1

のようなセキュリティ ホールを除いて、名前がどこかで定義されているか、別のモジュールからインポートされていない限り、名前をeval使用することはできません。別のモジュールからの値に自動的かつ静かにアクセスさせる方法はありません。amapper.pymapper.pymapper.pya

さらに、例のように dict でのみ使用している場合はa.foo、dict が作成されるとすぐに評価されます。実際に関数を呼び出すまで待つ必要はありません。辞書を作成するために評価されるとすぐに、何がa.foo何であるかがわからないため失敗しaます。

この 2 番目の問題は、要素を関数でラップすることで回避できます (簡潔にするためにラムダを使用します)。

Mapper = {'test': lambda: a.foo}

. . . aしかし、どうにかして内部で利用できるようにならない限り、これはまだ役に立ちませんmapper.py

1つの可能性は、「ミステリー」オブジェクトでパラメーター化Mapperし、そのオブジェクトを外部から渡すことです。

# mapper.py
Mapper = {'test': lambda a: a.foo}

# other module
from mapper import Mapper
Mapper['test'](a)()

または、提案されたのと同様に、何らかの方法でオブジェクトをmgilson「登録」できます。これにより、オブジェクトを一度だけ渡して登録することができ、呼び出しごとに渡す必要がなくなります。aMappera

# mapper.py
Mapper = {'test': lambda a: Mapper['a'].foo}

# other module
from mapper import Mapper
Mapper['a'] = a
Mapper['test']()()

最後に 2 組の括弧があることに注意してください。1 組はラムダを評価して呼び出したい関数を抽出するためのもので、2 番目の組は実際にその関数を呼び出すためのものです。参照として使用する代わりにMapper['a']、モジュール レベルの変数を使用して、同様の処理を行うことができます。

# mapper.py
Mapper = {'test': lambda: a.foo}

# other module
import mapper
Mapper = mapper.Mapper

mapper.a = a
Mapper['test']()()

import mapperこれは、他のモジュールでモジュール変数を設定するために行う必要があることに注意してください。

Mapper通常の dict の代わりにカスタムクラス for を使用し、そのクラス__getitem__に「既知の場所」を調べて (たとえば、モジュール変数を読み取って) 評価のベースとして使用することで、これをいくらか合理化できaます。ただし、それはより重いソリューションになります。

肝心なのは、未定義の variable を使用するevalコードを(再び、または他のそのような穴を使用せずに) 記述し、別のモジュールで変数を定義して、それを自動的に認識することができないということです。使用する値を「伝える」コード行がどこかにある必要があります。mapper.pyaamapper.pymapper.pya

于 2013-02-12T19:36:41.633 に答える
0

私が完全にフォローしているかどうかはわかりませんが、Mapperへの参照を持つどこからでもaメソッドを「登録」できます。Mapper

#mapping.py
Mapper = {}

その後:

#main.py
from mapping import Mapper

#snip
a = A()
Mapper['test'] = a.foo #put your instance method into the Mapper dict.
#snip

Mapper['test']()
于 2013-02-12T18:10:07.537 に答える