【问题标题】:How to mix *args, **kwargs and named arguments in decorator如何在装饰器中混合 *args、**kwargs 和命名参数
【发布时间】:2014-04-26 09:41:09
【问题描述】:

我想创建一个自定义装饰器,名为captain_hook。它应该存储 hooks - 在装饰函数之前调用的函数 - 并调用它们:

def captain_hook(func):
    def closure(hooks=[], *args, **kwargs):
        for hook in hooks: 
            hook(*args, **kwargs)
        return func(*args, **kwargs)
    return closure

现在我可以说:

@captain_hook
def sum(a, b):
    return a+b
sum.__defaults__[0].append(lambda arg: sys.stdout.write(str(arg))) #this lambda function prints argument
sum(1, 2) #should write (1, 2) and return 3

问题是我无法将参数传递给closure,导致args 的第一个元素错误地解包为hooks 参数:sum(1, 2) 设置hook=1a=2b - undefined。我该怎么做?

【问题讨论】:

  • 你打算什么时候通过钩子?按照您的设置方式,您在使用captain_hook 时不指定任何挂钩,在调用sum 时也不提供任何挂钩,因此不涉及挂钩。你想在函数定义时或调用时指定钩子吗?
  • @BrenBarn 我编辑了问题。在调用该函数之前,我将安装钩子。当我创建新对象时,它将受到函数调用的影响并且应该适应变化,它的钩子将被调用。通过更改sum.__defaults__ 来安装挂钩。

标签: python arguments decorator


【解决方案1】:

修改__defaults__ 是一种非常可疑的处理方式。 __defaults__ 用于参数默认值。如果您的钩子不作为参数传递,则不应将它们存储为参数默认值。

如果你真的希望以后能够修改钩子,你应该让你的装饰器成为一个自己存储钩子的类。这是一个例子:

class CaptainHook(object):
    def __init__(self, func):
        self.hooks = []
        self.func = func

    def __call__(self, *args, **kwargs):
        for hook in self.hooks:
            hook(*args, **kwargs)
        return self.func(*args, **kwargs)

然后:

>>> @CaptainHook
... def sum(a, b):
...     return a+b
>>> sum(1, 2)
3
>>> def aHook(*args, **kwargs):
...     print "I am a hook!"
>>> sum.hooks.append(aHook)
>>> sum(1, 2)
I am a hook!
3

【讨论】:

  • 正如我所想,你已经写好了。谢谢你的好样本,你的方法好多了,我的方法太老套了。
猜你喜欢
  • 2018-08-28
  • 2013-09-25
  • 1970-01-01
  • 1970-01-01
  • 2018-04-05
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
相关资源
最近更新 更多