Python - checking parameters using an exception

I am trying to write an exception code to exclude code in my Python code to ensure that the parameters passed to the function satisfy the relevant conditions (i.e. required parameter parameters, type checking parameters, setting limit values ​​for parameters, etc ..) . I understand satisfactorily how to manually create exceptions and also handle them .

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

This is an acceptable (tested and verified) way to check parameters in Python, but I need to ask a question: since Python has no way to write Switch-case messages other than if-then-else statements, is there a more efficient or correct way to accomplish this task? Or implements long segments of if-then-else statements is my only option?

+5
source share
3 answers

You can create a decorator function and pass expected types and (optional) ranges as parameters. Something like that:

 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 

Instead of if ...: raise you can also invert the conditions and use assert , but as noted in the comments , this may not always be true. You can also expand this to allow, for example, to open ranges (e.g. (0., None) ) or to accept arbitrary ( lambda ) functions for more specific checks.

Example:

 @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 
+2
source

I think you can use a decorator to check the parameters.

 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'> 
+1
source

This pushed me for a while to Python, there is no standard way of output if the provided parameter is None or has an absent value, and also does not process the JSON / Dict object gracefully,

for example, I want to display the actual parameter name in the error message,

 username = None if not username: log.error("some parameter is missing value") 

It is not possible to pass the actual parameter name unless you do this artificially and randomly by hard-coding the parameter in the error message, i.e.

 if not username: log.error("username is missing value") 

but it is random and prone to syntax errors, and the pain in the butt to maintain.

For this reason, I wrote the Dictator function,

https://medium.com/@mike.reider/python-dictionaries-get-nested-value-the-sane-way-4052ab99356b

If you add your parameters to the dict or read your parameters from the YAML or JSON configuration file, you can tell the Dictator to raise the ValueError value if the parameter is null,

eg,

config.yaml

 skills: sports: - hockey - baseball 

now your py program reads in this configuration file, and parameters, like JSON dict,

 with open(conf_file, 'r') as f: config = yaml.load(f) 

now set your parameters and also check if theyre NULL

 sports = dictator(config, "skills.sports", checknone=True) 

If the sport is not None, it will raise the ValueError value, telling you which parameter is missing

 ValueError("missing value for ['skills']['sports']") 

you can also provide a fallback value for your parameter, so if it is None, give it a fallback default value,

 sports = dictator(config, "skills.sports", default="No sports found") 

This avoids the ugly exceptions for Index / Value / Key errors.

Its flexible, elegant way of processing large dictionary data structures, and also gives you the ability to check your program parameters for Null values ​​and display the actual parameter names in an error message

0
source

All Articles