Python decoder to display passed and default kwargs

I am new to python and decorators, and I am confused about writing a decorator that reports not only passed args and kwargs, but also immutable kwargs by default.

This is what I still have.

def document_call(fn):
    def wrapper(*args, **kwargs):
        print 'function %s called with positional args %s and keyword args %s' % (fn.__name__, args, kwargs)
        return fn(*args, **kwargs)
    return wrapper

@document_call
def square(n, trial=True, output=False):
    # kwargs are a bit of nonsense to test function
    if not output:
        print 'no output'
    if trial:
        print n*n

square(6) # with this call syntax, the default kwargs are not reported
# function square called with positional args (6,) and keyword args {}
# no output
36

square(7,output=True) # only if a kwarg is changed from default is it reported
# function square called with positional args (7,) and keyword args {'output': True}
49

The "problem" is that this decorator reports arguments that are passed in the call with a square, but do not report the default values ​​defined in the quadratic definition. The only way to tell kwargs is if they are changed from their default values, i.e. transferred to a square call.

Any recommendations on how I can get quarts in a quadratic definition are also reported?

, . , , , .

import inspect
def document_call(fn):
    def wrapper(*args, **kwargs):            
            argspec = inspect.getargspec(fn)
            n_postnl_args = len(argspec.args) - len(argspec.defaults)
        # get kwargs passed positionally
        passed = {k:v for k,v in zip(argspec.args[n_postnl_args:], args[n_postnl_args:])}
        # update with kwargs
        passed.update({k:v for k,v in kwargs.iteritems()})            
        print 'function %s called with \n  positional args %s\n  passed kwargs %s\n  default kwargs %s' % (
                fn.__name__, {k:v for k,v in zip(argspec.args, args[:n_postnl_args])},
                passed,
                {k:v for k,v in zip(argspec.args[n_postnl_args:], argspec.defaults) if k not in passed})        
        return fn(*args, **kwargs)
return wrapper

. . !

+5
4

, , . inspect.getargspec().

, , . , ; , :

import inspect

argspec = inspect.getargspec(fn)
positional_count = len(argspec.args) - len(argspec.defaults)
defaults = dict(zip(argspec.args[positional_count:], argspec.defaults))

, , , :

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 with positional args %s and keyword args %s' % (
            fn.__name__, args[:positional_count], 
            {k: used_kwargs.get(k, d) for k, d in defaults.items()})
        return fn(*args, **kwargs)
    return wrapper

, positional, , , .

:

>>> square(39)
function square called with positional args (39,) and keyword args {'trial': True, 'output': False}
no output
1521
>>> square(39, False)
function square called with positional args (39,) and keyword args {'trial': False, 'output': False}
no output
>>> square(39, False, True)
function square called with positional args (39,) and keyword args {'trial': False, 'output': True}
>>> square(39, False, output=True)
function square called with positional args (39,) and keyword args {'trial': False, 'output': True}
+6

wrapper , , .

, , . , inspect .

inspect.getargspec, . :

def document_call(fn):
    argspec = inspect.getargspec(fn)
    defaultArguments = list(reversed(zip(reversed(argspec.args), reversed(argspec.defaults))))

    def wrapper(*args, **kwargs):
        all_kwargs = kwargs.copy()
        for arg, value in defaultArguments:
            if arg not in kwargs:
                all_kwargs[arg] = value

        print 'function %s called with positional args %s and keyword args %s' % (fn.__name__, args, all_kwargs)

        # still make the call using kwargs, to let the function handle its default values
        return fn(*args, **kwargs)
    return wrapper

, , . , square trial, n. , kwargs. , . argspec.

+1

, python3

import inspect
import decorator

@decorator.decorator
def log_call(fn,*args, **kwargs):
    sign = inspect.signature(fn)
    arg_names = list(sign.parameters.keys())
    passed = {k:v for k,v in zip(arg_names[:len(args)], args)}
    passed.update({k:v for k,v in kwargs.items()})
    params_str = ", ".join([f"{k}={passed.get(k, '??')}" for k in arg_names])
    print (f"{fn.__name__}({params_str})")
    return fn(*args, **kwargs)

, "", .

0

Python 3.6 inspect.getfullargspec:

def document_call(func):
    @wraps(func)
    def decorator(*args, **kwargs):
        fullargspec = getfullargspec(func)
        default_kwargs = fullargspec.kwonlydefaults
        print('Default kwargs', default_kwargs)
        print('Passed kwargs', kwargs)
        return func(*args, **kwargs)
    return decorator

* ,

@document_call
def square(n, *, trial=True, output=False):
    # kwargs are a bit of nonsense to test function
    if not output:
        print 'no output'
    if trial:
        print n*n

0

Source: https://habr.com/ru/post/1624618/


All Articles