显示传递和默认 kwargs 的 python 装饰器

标签 python decorator default python-decorators keyword-argument

我是 python 和装饰器的新手,并且很难编写一个装饰器,它不仅报告传递的 args 和 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 时传递的参数,但不报告在 square 定义中定义的默认 kwargs。报告 kwargs 的唯一方法是将它们从默认值更改,即传递给 square 调用。

对于如何在报告的方形定义中得到 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

那是一次很好的学习经历。看到同一个问题的三种不同解决方案是很好的。感谢回答者!

最佳答案

您必须反省包装的函数,才能读取默认值。您可以使用 inspect.getargspec() function 执行此操作.

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

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

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

演示:

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

关于显示传递和默认 kwargs 的 python 装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34832573/

相关文章:

python - Matplotlib FuncAnimation,当 blit = true 时出错。

python - 如何在 Pandas 数据框的列中用零替换 NaN 值?

python - 为什么 tf.gradient 和 tf.where 返回 None ?

python - 多个 python 装饰器

java - 装饰器模式(我可能滥用)的问题

python - 在 Python 2.7 中定义类似 "property"的装饰器

scala - 为什么 Scala 编译器不允许使用默认参数的重载方法?

c# - 如何更改 C# 中的 default(T) 返回值?

java - 当在字段上设置默认值时,JPA/Hibernate 插入 NULL

python - View 中的 Django 选择引用