python decorator to display passed AND default kwargs -
i new python , decorators , stumped in writing decorator reports not passed args , kwargs unchanged default kwargs.
this have far.
def document_call(fn): def wrapper(*args, **kwargs): print 'function %s called positional args %s , keyword args %s' % (fn.__name__, args, kwargs) return fn(*args, **kwargs) return wrapper @document_call def square(n, trial=true, output=false): # kwargs bit of nonsense test function if not output: print 'no output' if trial: print n*n square(6) # call syntax, default kwargs not reported # function square called positional args (6,) , keyword args {} # no output 36 square(7,output=true) # if kwarg changed default reported # function square called positional args (7,) , keyword args {'output': true} 49 the 'problem' decorator reports args passed in call square not report default kwargs defined in square definition. way kwargs reported if they're changed default i.e. passed square call.
any recommendations how kwargs in square definition reported too?
edit after following on inspect suggestions, helped me solution below. changed output of positional params include names because thought made output easier understand.
import inspect def document_call(fn): def wrapper(*args, **kwargs): argspec = inspect.getargspec(fn) n_postnl_args = len(argspec.args) - len(argspec.defaults) # kwargs passed positionally passed = {k:v k,v in zip(argspec.args[n_postnl_args:], args[n_postnl_args:])} # update kwargs passed.update({k:v k,v in kwargs.iteritems()}) print 'function %s called \n positional args %s\n passed kwargs %s\n default kwargs %s' % ( fn.__name__, {k:v k,v in zip(argspec.args, args[:n_postnl_args])}, passed, {k:v k,v in zip(argspec.args[n_postnl_args:], argspec.defaults) if k not in passed}) return fn(*args, **kwargs) return wrapper that learning experience. it's neat see 3 different solutions same problem. answerers!
you'll have introspect function wrapped, read defaults. can inspect.getargspec() function.
the function returns tuple with, among others, sequence of argument names, , sequence of default values. last of argument names pair defaults form name-default pairs; can use create dictionary , extract unused defaults there:
import inspect argspec = inspect.getargspec(fn) positional_count = len(argspec.args) - len(argspec.defaults) defaults = dict(zip(argspec.args[positional_count:], argspec.defaults)) you'll need take account positional arguments can specify default arguments too, dance figure out keyword arguments little more involved looks this:
def document_call(fn): argspec = inspect.getargspec(fn) positional_count = len(argspec.args) - len(argspec.defaults) defaults = dict(zip(argspec.args[positional_count:], argspec.defaults)) def wrapper(*args, **kwargs): used_kwargs = kwargs.copy() used_kwargs.update(zip(argspec.args[positional_count:], args[positional_count:])) print 'function %s called positional args %s , keyword args %s' % ( fn.__name__, args[:positional_count], {k: used_kwargs.get(k, d) k, d in defaults.items()}) return fn(*args, **kwargs) return wrapper this determines keyword paramaters used both positional arguments passed in, , keyword arguments, pulls out default values not used.
demo:
>>> square(39) function square called positional args (39,) , keyword args {'trial': true, 'output': false} no output 1521 >>> square(39, false) function square called positional args (39,) , keyword args {'trial': false, 'output': false} no output >>> square(39, false, true) function square called positional args (39,) , keyword args {'trial': false, 'output': true} >>> square(39, false, output=true) function square called positional args (39,) , keyword args {'trial': false, 'output': true}
Comments
Post a Comment