2013-05-14 3 views
3

몇 가지 관련 답변을 찾았지만 원하는 것은 아닙니다. 여기 문자열의 파이썬 동적 함수

내가 지금 가지고있는 코드입니다 :

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) 

편집 : 데이터베이스가 신뢰할 수있는, 그래서 santize 또는 악성 코드에 대해 걱정할 필요가 없습니다.

답변

1

람다 객체 인 __code__을 대체하면 기본적으로 함수를 재정의합니다. 새 argcount는 __code__.co_argcount에 의해 결정되므로 람다가 어느 인수를 취했는지 또는 얼마나 많이 인수했는지는 중요하지 않습니다. 당신이 당신의 컴파일 된 코드에 매개 변수를 전달하려면

, 당신은 locals dictionaray에 매개 변수를 전달, 직접 eval 코드 개체에 시도 할 수 :

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' 모드로 컴파일해야합니다. 즉, 코드를 표현식으로 제한해야하며 명령문을 포함 할 수 없습니다.