2016-07-28 22 views
5

jestem próby zapisu wyjątku podnoszenie bloków kodu do mojego kodu Pythona w celu zapewnienia, że ​​parametry przekazywane do funkcji spełniać odpowiednie warunki (tj dokonywania parametry obowiązkowy parametrów typu sprawdzania, ustanawiając granicę wartości parametrów, itp.). Rozumiem w sposób zadowalający, jak manually raise exceptions, a także handling them.Python - parametr kontroli z Exception Podnoszenie

from numbers import Number 

def foo(self, param1 = None, param2 = 0.0, param3 = 1.0): 
    if (param1 == None): 
     raise ValueError('This parameter is mandatory') 
    elif (not isinstance(param2, Number)): 
     raise ValueError('This parameter must be a valid Numerical value') 
    elif (param3 <= 0.0): 
     raise ValueError('This parameter must be a Positive Number') 
    ... 

To było dopuszczalne (wypróbowane i prawdziwe) sposób parametr kontroli w Pythonie, ale muszę się zastanawiać: Ponieważ Python nie mają sposób pisać rozdzielnie przypadków oprócz if-then-else, jest istnieje bardziej wydajny lub właściwy sposób wykonania tego zadania? Lub może wdrażać długie wyciągi instrukcji if-then-else jako jedyną opcję?

+1

Można by stworzyć dekorator funkcji, coś takiego '@check (typ = [None, None, pływak, float] waha = [None, None (0.0,10.0), None])' (tutaj , 'Brak' oznaczający" bez ograniczeń ") –

+2

Może to ci pomoże: http://stackoverflow.com/questions/15299878/how-to-use-python-decorators-to-check-function-arguments –

+0

Wierz lub nie, myślę, że używanie instrukcji assert może być dla mnie bardziej korzystne niż użycie instrukcji if-elif. Wpadłem na pomysł, zarówno po sprawdzeniu linku zamieszczonego w komentarzach, jak i kodzie użytym do dekoratora. Dzięki, chłopaki! –

Odpowiedz

2

Można by utworzyć funkcję dekoratora i przekazać spodziewanych rodzajów i (opcjonalnie) waha się jako parametry. Coś takiego:

def typecheck(types, ranges=None): 
    def __f(f): 
     def _f(*args, **kwargs): 
      for a, t in zip(args, types): 
       if not isinstance(a, t): 
        raise ValueError("Expected %s got %r" % (t, a)) 
      for a, r in zip(args, ranges or []): 
       if r and not r[0] <= a <= r[1]: 
        raise ValueError("Should be in range %r: %r" % (r, a)) 
      return f(*args, **kwargs) 
     return _f 
    return __f 

Zamiast if ...: raise można także odwrócić i używać assert warunki, ale jak noted in comments te nie zawsze mogą być wykonywane. Można również rozszerzyć to, aby umożliwić np. zakresy otwarte (np. (0., None)) lub akceptowanie dowolnych (lambda) funkcji dla bardziej szczegółowych kontroli.

Przykład:

@typecheck(types=[int, float, str], ranges=[None, (0.0, 1.0), ("a", "f")]) 
def foo(x, y, z): 
    print("called foo with ", x, y, z) 

foo(10, .5, "b") # called foo with 10 0.5 b 
foo([1,2,3], .5, "b") # ValueError: Expected <class 'int'>, got [1, 2, 3] 
foo(1, 2.,"e") # ValueError: Should be in range (0.0, 1.0): 2.0 
+0

Bardzo szczegółowa i dokładna odpowiedź! I bardzo szybko dostarczone, mogę dodać! Clap and a half do ciebie! –

1

myślę, że można użyć dekorator sprawdzić parametry.

def parameterChecker(input,output): 
...  def wrapper(f): 
...   assert len(input) == f.func_code.co_argcount 
...   def newfun(*args, **kwds): 
...    for (a, t) in zip(args, input): 
...     assert isinstance(a, t), "arg {} need to match {}".format(a,t) 
...    res = f(*args, **kwds) 
...    if not isinstance(res,collections.Iterable): 
...     res = [res] 
...    for (r, t) in zip(res, output): 
...     assert isinstance(r, t), "output {} need to match {}".format(r,t) 
...    return f(*args, **kwds) 
...   newfun.func_name = f.func_name 
...   return newfun 
...  return wrapper 

example: 
@parameterChecker((int,int),(int,)) 
... def func(arg1, arg2): 
...  return '1' 
func(1,2) 
AssertionError: output 1 need to match <type 'int'> 

func(1,'e') 
AssertionError: arg e need to match <type 'int'>