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
Post a Comment