2016-10-19 2 views
-5

사용자 입력에서 함수를 호출하고 싶지만 인수는 괄호 안에 포함하고 싶습니다. 예를 들어, 나는 하나 개의 인수받는 함수가있는 경우 :사용자 입력을 기반으로 인수가있는 Python 함수를 호출하십시오.

def var(value): 
    print(value) 

내가 다음 인수와 함께 함수를 호출 명령 및 인수에 대한 사용자를 부탁드립니다 :

Input Command: var("Test") 
Test 
+6

호출 및 인수를 캡처하고 호출을 파싱하려면 파서를 작성해야합니다. 신뢰할 수없는 입력에'eval'을 사용해서는 안됩니다. – davidism

+0

@ davidism 정의한 함수에만'eval'을 사용할 수 있습니까? – MasterHolbytla

+0

@MasterHolbytla는 항상'var (arg1, arg2, arg3)'만큼 간단한 입력이 될 것입니까? 아니면 더 복잡합니까? – idjaw

답변

9

하게 분할을 인수에서 함수 이름. 사전 정의 된 맵을 사용하여 함수를 이름으로 찾습니다. 인수를 literal_eval으로 구문 분석하십시오. 인수를 사용하여 함수를 호출하십시오.

available = {} 

def register_func(f): 
    available[f.__name__] = f 

@register_func 
def var(value): 
    print(value) 

from ast import literal_eval 

def do_user_func(user_input): 
    name, args = user_input.split('(', 1) 
    return available[name](*literal_eval('(' + args[:-1] + ',)')) 

do_user_func("var('test')") # prints "test" 

이것은 무효 입력 (예 잊고 괄호 또는 잘못된 함수 이름) 실패 여전히 엄청나게 취성이다. 더 강력하게 만드는 것은 당신에게 달려 있습니다.

literal_eval은 많은 양의 메모리로 평가되는 작은 문자열을 구성 할 수 있으므로 신뢰할 수없는 입력에서는 여전히 안전하지 않습니다. '[' * 10 + ']' * 10, 안전하지만 시범적인 예입니다.

마지막으로 은 신뢰할 수없는 사용자 입력eval을 사용하지 마십시오. There is no practical way to secure it from malicious input. 예상되는 멋진 입력을 평가하는 동안, 예를 들어 모든 파일을 삭제할 코드도 평가합니다.

+0

'eval'을'dir()'카테고리에서 색인하려고 했으므로 원하는대로 할 수 있습니다. 이론에 의하면. – MasterHolbytla

+5

@ MasterHolbytla 그게 무슨 뜻인지 전혀 모르겠지만, 아니, 갑자기 'eval'이 안전하지 않다고 수정하지 않았습니다. 나는 그것을 보증한다. – davidism

+0

동의합니다. 나는 단지'eval' 승인 함수들에 대해서만 일할 것이다. – MasterHolbytla

3

난 당신 같은 간단한 입력 다루고있는 가정하에, 대안으로이 솔루션을 게시 할 예정입니다 :

var(arg) 

또는 위치의 목록을 취할 수있는 하나의 함수 호출 인수.

eval을 사용하면 이미 언급 한 것처럼 끔찍한 권장하지 않는 아이디어가됩니다. 제 생각에 그것은 당신이 읽었던 보안 위험이라고 생각합니다.

이 방법을 수행하는 가장 좋은 방법은 실행하려는 메서드에 문자열을 매핑하는 사전을 만드는 것입니다.

또한이 작업을 수행 할 수있는 다른 방법을 고려해 볼 수 있습니다. 인수를 사용하여 함수를 호출하는 방법을 알기 위해 공백으로 분리 된 입력이 있어야합니다. 이 같은 입력을 고려 : 그래서

"var arg1 arg2" 

을 할 때 입력하는 것이 : 당신은 지금해야합니다

call = input().split() 

:

['var', 'arg1', 'arg2'] 

이제 첫 번째 인수 기능, 그리고 모든 것을 고려할 수 있습니다 그렇지 않으면 함수에 전달할 인수를 가져옵니다. 그래서, 기능 예를 들어 :

def var(some_arg, other_arg): 
    print(some_arg) 
    print(other_arg) 

d = {"var": var} 

call = input().split() 

d[call[0]](*call[1:]) 

데모 :

var foo bar 
foo 
bar 
0

대신 평가를 사용하여, 당신은 스스로를 구문 분석 할 수 있습니다. 이렇게하면 각 함수가 사용자 입력의 인수를 구문 분석/역 직렬화하는 방법을 제어 할 수 있습니다.당신이 좀 더 오류 검사 및 역 직렬화 기능을 개선하고 기능 추가를 모듈화에 의해 얻을 수 있지만

import sys, re 

def custom_print(value): 
    print value 

def custom_add(addends): 
    print sum(addends) 

def deserialize_print(args): 
    # just print it as is 
    custom_print(args) 

def deserialize_add(args): 
    # remove all whitespace, split on commas, parse as floats 
    addends = [float(x) for x in re.sub(r"\s", "", args).split(",")] 
    # send to custom_add function 
    custom_add(addends) 

def get_command(): 
    cmd_input = raw_input("Command: ") 
    # -- check that the command is formatted properly 
    # and capture command groups 
    match = re.match(r"^([a-zA-Z0-9]+)(\(.*\))?$", cmd_input) 
    if match: 
     # extract matched groups to separate variables 
     (cmd, argstring) = match.groups() 

     # strip parenthesis off of argstring 
     if argstring: 
      args = argstring[1:-1] 

     # send the whole argument string to its corresponding function 
     if cmd == "print": 
      deserialize_print(args) 
     elif cmd == "add": 
      deserialize_add(args) 
     elif cmd == "exit": 
      sys.exit() 
     else: 
      print "Command doesn't exist." 
    else: 
     print "Invalid command." 

    # recurse until exit 
    get_command() 


# -- begin fetching commands 
get_command() 

이것은 꽤 거친 설정입니다.

분리 된 deserialize 함수가 너무 많이 보인다면 사용자 지정 함수 자체로 deserialization을 이동할 수도 있습니다.

2

cmd 모듈을 조사해야합니다. 이것은 셸 명령과 유사한 입력을 구문 분석 할 수 있지만 괄호가 명세의 중요한 부분 인 경우 구분자를 변경하고 구분 기호를 변경할 수 있다고 생각합니다.

관련 문제