4

関連する回答はほとんど見つかりませんでしたが、私が望むものではありませんでした。

ここに私が今持っているコードがあります:

code_str = """
print "this is my global x = " + x
print "And another line is done"
"""

x = 'mystery'

func_template = lambda p: None

func_template.__code__ = compile(code_str, '<string>', 'exec')
func_template() # this executes fine and also has access to x, which i do need.
# func_template('param') # This raises: TypeError: <module>() takes no arguments (1 given)

いくつかの背景。code_str はデータベースから取得されます。次のように、名前で任意の関数を呼び出すことができるように、多くの関数を dict に格納する必要があります。

all_funcs = {}

# Assuming db_result returns a list of name, code tuples from the databse

for name, code in db_result:
    all_funcs[name] = my_compile(code)

名前がわかっている場合は、必要な引数を使用して必要な関数を呼び出すだけです。

result = all_funcs[by_name](arg1, arg2)

編集: データベースは信頼されているため、悪意のあるコードを消毒したり心配したりする必要はありません。

4

1 に答える 1

2

__code__ラムダのオブジェクトを置き換えると、基本的に関数を再定義します。新しい argcount は によって決定される__code__.co_argcountため、ラムダが以前に取った引数の数または数は関係ありません。

コンパイルされたコードにパラメーターを渡したい場合はeval、コード オブジェクトに直接試して、localsdictionarayでパラメーターを渡すことができます。

code_str = """
print "this is my global x = " + x
print "And another line is done"
print param
"""

compiled = compile(code_str, "<string>", "exec")
func_template = lambda p=None: eval(compiled, globals(), {'param': p})

x = "1"
func_template()
func_template("2")

この方法では、明らかにキーワード引数のみを渡すことができ、位置引数を使用することはできません。使用することもできます

func_template = lambda **kwargs: eval(compiled, globals(), **kwargs)

関数に与えられたキーワード引数を直接渡します。

関数からの戻り値が必要な場合は、'eval'代わりにモードでコードをコンパイルする必要があります。つまり、コードを式に制限する必要があり、ステートメントを持つことはできません。

于 2013-05-14T08:41:57.277 に答える