python - How to use a decorator to check arguments -


i have several functions want give default arguments. since these defaults should newly-initialized objects, can't set them defaults in argument list. introduces lot of clunky code default them none , check in every single function

def functionwithdefaults(foo=none):   if foo none:     foo = makenewobject() 

to reduce repeated code, made decorator initialize parameters.

@initializedefaults(makenewobject, 'foo') def functionwithdefaults(foo=none):   # if foo wasn't passed in, equal makenewobject() 

the decorator wrote such:

def initializedefaults(initializer, *parameters_to_initialize):   """returns decorator initialize parameters uninitialized.    args:     initializer: function called no arguments generate         values parameters need initialized.     *parameters_to_initialize: each arg name of parameter         represents user key.   """   def decorator(func):     def _initializedefaults(*args, **kwargs):       # gets list of names of variables in func.  so, if       # function being decorated takes 2 arguments, foo , bar,       # func_arg_names ['foo', 'bar'].  way, can tell whether or       # not parameter passed in positional argument.       func_arg_names = inspect.getargspec(func).args       num_args = len(args)       parameter in parameters_to_initialize:         # don't set default if parameter passed positional arg.         if num_args <= func_arg_names.index(parameter):           # don't set default if parameter passed keyword arg.           if parameter not in kwargs or kwargs[parameter] none:             kwargs[parameter] = initializer()       return func(*args, **kwargs)     return _initializedefaults   return decorator 

that works great if need decorate once, breaks multiple decorations. specifically, suppose want initialize foo , bar separate variables:

@initializedefaults(makenewobject, 'foo') @initializedefaults(makeotherobject, 'bar') def functionwithdefaults(foo=none, bar=none):   # foo should makenewobject() , bar should makeotherobject() 

that breaks because in second decorator, func_arg_defaults gets arguments of first decorator rather functionwithdefaults. result, can't tell whether or not parameter has been passed in positionally.

is there clean way solve problem?

things don't work:

  • functools.wraps(func) makes __name__ of function decorated function, doesn't change arguments (unless there's different way it).
  • inspect.getcallargs doesn't raise exception in second decorator
  • using func.func_code.co_varnames doesn't provide function's arguments in second decorator

i use 1 decorator, seems less clean, , feels there should cleaner solution.

thanks!

this might best advice you'd decorators in python: use wrapt.decorator.

it make task of writing decorators simpler (you don't need write function inside function inside function), , avoid errors makes when writing simple decorators. learn are, might want read graham dumpleton's blog posts titled "how implemented python decorator wrong" (he convincing)


Comments

Popular posts from this blog

javascript - RequestAnimationFrame not working when exiting fullscreen switching space on Safari -

jquery - Keeping Kendo Datepicker in min/max range -

jsf - How to ajax update an item in the footer of a PrimeFaces dataTable? -