2013-05-14 3 views
3

Я столкнулся с несколькими связанными ответами, но не с тем, что хочу.Динамические функции Python из строк

Вот код, у меня сейчас:

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 будет приходить из базы данных, и мне нужно хранить много функций в Словаре, так что я могу назвать какой-либо один по имени, как показано ниже:

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) 

Edit: база данных является доверенным, так что я не нужно santize или беспокоиться о вредоносных программ.

ответ

1

Если вы замените объект лямбда __code__, вы в основном переопределите функцию. Новый аргумент определяется __code__.co_argcount, поэтому не имеет значения, какое или сколько аргументов лямбда взяла раньше.

Если вы хотите передать параметр в скомпилированный код, вы могли бы попытаться eval код объекта напрямую, минуя свой параметр в locals dictionaray:

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', что означает, что вам нужно ограничить свой код выражениями и не иметь операторов.