2017-09-20 9 views
0

가 나는 경우이 같은 선택이 기능을 많이 구현해야합니다에 따르면입력이 불법 인 경우 법적 인수 목록을 출력하는 방법은 무엇입니까?

def foo1(bar1): 
    if bar1 == 'A': 
     do something 
    elif bar1 == 'B': 
     do something 
    elif ... 
    ... 
    else: 
     raise ValueError('legal input of bar1 should be {}'.format(list_of_bar)) 

def foo2(bar2): 
    if bar2 == 'A': 
     do something 
    elif bar2 == 'B': 
     do something 
    elif ... 
    ... 
    else: 
     raise ValueError('legal input of bar2 should be {}'.format(list_of_bar)) 

''' 

을 인상 오류의 마지막 단계를 반복하지 않도록하고 인쇄 할 수있는 방법이있다 "스스로를 반복하지 마십시오" 올바른 인수 목록? 나는 데코레이터가 이것을 할 수도 있다고 생각했지만 그것을 만드는 방법을 확신하지 못했습니다. 미리 감사드립니다.

업데이트

inspect 모듈을 사용하여 직접 구현했습니다. 하지만 난 여전히 몇 가지 조언 또는 더 나은 솔루션

import inspect 
from functools import wraps 
import re 

def test_none(func): 
    _code = inspect.getsource(func) 
    _list = re.findall(r'if (\w+) == (\w+)', _code) 
    assert all(_list[0][0] == name for name, case in _list) 
    _arg = _list[0][0] 
    _case = tuple(case for name, case in _list) 

    @wraps(func) 
    def wrapper(*args, **kwargs): 
     results = func(*args, **kwargs) 
     if results is None: 
      raise ValueError(
        'Legal value of \'{arg}\' should be anyone of {case}'.format(
        arg=_arg, case=_case)) 
     return results 
    return wrapper 

@test_none 
def foo(bar): 
    if bar == 0: 
     return 1 
    elif bar == 1: 
     return 2 

시험 예를 얻을 수 있기를 바랍니다 :

foo(3) 
ValueError: Legal value of 'bar' should be anyone of ('0', '1') 
+2

당신은' "A"를'매핑 뭔가를 찾고있어 ''뭔가하고 싶다',''B ''를''다른 것을해라 ', 등등. –

+0

그러나 사전을 사용하면 최종 인상 오류 및 인쇄 단계를 수행해야합니다.이 단계는 데코레이터 또는 다른 "흑 마법"에 의해 실제로 피하고 싶습니다. –

답변

1

내가 일반적으로 '대부분의 경우'패턴이 더 명확하게 사전으로 표현되는 것을 찾을 수 있습니다.

각각의 경우에 대해 호출 할 다른 함수가 있다고 가정하겠습니다. 그러나 각 값이 반환하려는 정수이거나 다른 객체 인 경우 패턴이 작동한다고 가정합니다.

CASES 사전은 명확하고 컴팩트하게 코드의 독자에게 서로 다른 사례를 알립니다.

CASES = { 
    'A': do_something, 
    'B': do_something_else, 
    ... 
} 

def foo(bar): 
    if bar not in CASES: 
     raise ValueError('legal input of bar should be {}'.format(list_of_bar)) 

    # do stuff 
    CASES[bar]() 

대신 '용서 요청, 허락하지 않음'패턴을 사용하는 것입니다. 나는이 특별한 경우에 위와 같이 명확하지 않다는 것을 안다.

def foo(bar): 
    try: 
     func = CASES[bar] 
    except KeyError: 
     raise ValueError(...) 
    # do stuff 
    func() 

또는 다른 방법으로 사전 .get 방법을 사용하지만, 나는 다시는이 특정 시나리오에 대한 첫 번째 방법만큼 명확하지 않다 생각합니다.

def foo(bar): 
    func = CASES.get(bar) 
    if func is None: 
     raise ValueError(...) 
    # do stuff 
    func() 
+0

나는 이러한 모든 반응을 좋아합니다. 그리고 각 패러다임에 대한 좋은 유스 케이스가 있다고 생각합니다. 잘 했어! –

+0

답변 해 주셔서 감사합니다. 그러나 정의 할 유사한 함수 foo가 많이 있다면 전체 구조가 상당히 중복됩니다. 오류 단계를 올리지 않고 "foo"함수를 사용하는 방법이 있는지 궁금 해서요. 마지막 단계에서 새 함수를 내뱉습니다. –

1

,이 같은 것을 행동으로 가능한 입력을 매핑하는 사전을 사용

def foo(bar): 
    def a(): 
     print('a():') 

    def b(): 
     print('b():') 

    def c(): 
     print('c():') 

    actions = {'A': a, 'B': b, 'C': c} 
    if bar in actions: 
     actions[bar]() 
    else: 
     raise ValueError('legal input of bar should be {}'.format(sorted(actions.keys()))) 

데모 :

>>> foo('A') 
a(): 
>>> foo('Z') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "x.py", line 15, in foo 
    raise ValueError('legal input of bar should be {}'.format(sorted(actions.keys()))) 
ValueError: legal input of bar should be ['A', 'B', 'C'] 
+0

예 사전은이 경우에 아주 잘 작동합니다. 미안하지만 명확하게 표현하지 못했지만 필요한 것은 "ValueError 인상"단계를 피하는 것입니다. 이 비슷한 구조를 가진 여러 함수가 필요하기 때문에 반복되는 raise 오류와 인쇄 단계를 우회 할 수있는 방법이 있다고 생각했습니다. 나는 이것이 약간의 메타 프로그래밍을 필요로 할지도 모른다고 생각했다. –