Python Decorator для отображения пройденных И по умолчанию kwargs

Я новичок в Python и декораторах и нахожусь в тупике при написании декоратора, который сообщает не только о переданных аргументах и ​​аргументах kwargs, но также и неизменных kwargs по умолчанию.

Это то, что я до сих пор.

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

Проблема заключается в том, что этот декоратор сообщает об аргументах, которые передаются в вызове square, но не сообщает kwargs по умолчанию, определенные в определении квадрата. Единственным способом сообщения о kwargs является то, что они изменяются со своих значений по умолчанию, то есть передаются в квадратный вызов.

Любые рекомендации о том, как я могу получить kwargs в определении квадрата тоже?

Отредактируйте после проверки предложений проверки, которые помогли мне найти решение ниже. Я изменил вывод позиционных параметров, чтобы включить их имена, потому что я думал, что это облегчило понимание вывода.

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

Это был хороший опыт обучения. Приятно видеть три разных решения одной и той же проблемы. Спасибо Отвечающим!

Ответы на вопрос(3)

Ваш ответ на вопрос