2016-07-28 1 views
5

Je tente d'écrire des blocs de code d'exception dans mon code Python afin de m'assurer que les paramètres passés à la fonction remplissent les conditions appropriées (ie rendre les paramètres obligatoires, vérifier les paramètres, établir les limites valeurs pour les paramètres, etc ...). Je comprends de manière satisfaisante comment manually raise exceptions ainsi que handling them.Python - Vérification des paramètres avec Exception Raising

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') 
    ... 

Ceci est un moyen de paramètre acceptable (essayé et vrai) vérifier en Python, mais je dois me demander: Depuis Python ne dispose pas d'une façon d'écrire commutateur-cas en plus if-then-ELSE, est y at-il une manière plus efficace ou appropriée d'effectuer cette tâche? Ou est la mise en œuvre de longues étendues d'instructions if-then-else ma seule option?

+1

Vous pouvez créer un décorateur de fonction, quelque chose comme '@check (types = [None, None, flotteur, flotteur], ranges = [None, None, (0.0,10.0), None])' (ici , 'None' signifiant" aucune restriction ") –

+2

Peut-être que cela va vous aider: http://stackoverflow.com/questions/15299878/how-to-use-python-decorators-to-check-function-arguments –

+0

Croyez-le ou non, je pense que l'utilisation d'affirmations assert pourrait être plus bénéfique pour moi que l'utilisation d'instructions if-elif. J'ai en fait eu l'idée à la fois d'examiner le lien posté dans les commentaires ainsi que le code utilisé pour le décorateur. Alors merci, les gars! –

Répondre

2

Vous pouvez créer une fonction décorateur et transmettre les types attendus et les plages (facultatives) en tant que paramètres. Quelque chose comme ceci:

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 

Au lieu de if ...: raise vous pouvez aussi inverser les conditions et l'utilisation assert, mais comme noted in comments ceux qui pourraient ne pas toujours être exécuté. Vous pouvez également étendre ceci pour permettre par ex. ouvrir des plages (comme (0., None)) ou accepter des fonctions arbitraires (lambda) pour des contrôles plus spécifiques.

Exemple:

@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

Réponse très détaillée et complète! Et très rapidement livré, je pourrais ajouter! Applaudissez et demi! –

1

Je pense que vous pouvez utiliser pour vérifier décorateur les paramètres.

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'>