python装饰器显示通过的AND默认kwargs [英] python decorator to display passed AND default kwargs

查看:62
本文介绍了python装饰器显示通过的AND默认kwargs的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是python和decorator的新手,为编写一个decorator而感到困惑,它不仅报告了传递的args和kwargs,而且还报告了未更改的默认kwargs。

I am new to python and decorators and am stumped in writing a decorator which reports not only passed args and kwargs but ALSO the unchanged default 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中传递的args,但不报告在square定义中定义的默认kwarg。报告kwarg的唯一方法是将其更改为默认值,即传递给平方调用。

The 'problem' is that this decorator reports the args that are passed in the call to square but does not report the default kwargs defined in the square definition. The only way kwargs are reported is if they're changed from their default i.e. passed to the square call.

关于如何在正方形定义中报告kwarg的任何建议太?

Any recommendations for how I get the kwargs in the square definition reported too?

根据检查建议进行编辑,这有助于我找到下面的解决方案。我更改了位置参数的输出以包括它们的名称,因为我认为它使输出更易于理解。

Edit after following up on the inspect suggestions, which helped me to the solution below. I changed the output of positional params to include their names because I thought it made the output easier to understand.

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

那是一次很好的学习经历。很高兴看到针对同一问题的三种不同解决方案。

That was a good learning experience. It's neat to see three different solutions to the same problem. Thanks to the Answerers!

推荐答案

您必须对包装的函数进行内省,以读取默认值。您可以使用 inspect.getargspec()进行此操作函数

You'll have to introspect the function that you wrapped, to read the defaults. You can do this with the inspect.getargspec() function.

该函数返回一个元组,其中包括所有自变量名称的序列和默认序列价值观。最后一个参数名称与默认值配对以形成名称-默认值对。您可以使用它来创建字典并从中提取未使用的默认值:

The function returns a tuple with, among others, a sequence of all argument names, and a sequence of default values. The last of the argument names pair up with the defaults to form name-default pairs; you can use this to create a dictionary and extract unused defaults from 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 to take into account that positional arguments can specify default arguments too, so the dance to figure out keyword arguments is a little more involved but looks like 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 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

这将从传入的位置参数和关键字参数中确定实际使用了哪些关键字参数,然后为未使用的参数提取默认值。

This determines what keyword paramaters were actually used from both the positional arguments passed in, and the keyword arguments, then pulls out default values for those not used.

演示:

>>> 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}

这篇关于python装饰器显示通过的AND默认kwargs的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆