带参数的Python装饰器类

问题描述 投票:0回答:1

我有一个简单的 Python 类,我想用它来将命名钩子添加到我正在编写的程序中。我尝试运行下面的代码并得到以下输出。


代码:

hooks = {}

class hook(object):
    def __init__(self, f, hook):
        if hook not in hooks:
            hooks[hook] = []

        hooks[hook].append({"module": f.__module__, "func": f})
        self.f = f

    def __call__(self, *args):
        f(*args)

@hook("test")
def testHook():
    print "hi"

输出:

Traceback (most recent call last):                       
  File "<stdin>", line 1, in <module>                    
TypeError: __init__() takes exactly 3 arguments (2 given)

我该如何解决这个问题?我正在使用Python 2.7

python python-2.7 hook metaprogramming python-decorators
1个回答
6
投票

你的装饰器语法:

@hook("test")
def testHook():
    # ...

翻译为:

def testHook():
    # ...

testHook = hook("test")(testHook)

所以只给出了one参数。您需要重组代码以将类装饰器生成为hook()

返回值

以下方法可行:

def hook(hookname):
    class HookDecorator(object):
        def __init__(self, f):
            if hookname not in hooks:
                hooks[hookname] = []
    
            hooks[hook].append({"module": f.__module__, "func": f})
            self.f = f
    
        def __call__(self, *args):
            return self.f(*args)

    return HookDecorator

其中

__call__
使用
self.f
,而不是全局
f
,并返回修饰函数生成的任何内容。我假设
hooks
是某个地方的全局字典。

然而,将其作为一个类没有什么意义;你使用很少的状态。您也可以在这里使用包装器function

from functools import wraps

hooks = {}

def hook(hookname):
    def decorator(f):
        if hookname not in hooks:
            hooks[hookname] = []
    
        hooks[hookname].append({"module": f.__module__, "func": f})

        @wraps(f)
        def wrapper(*args):
            return f(*args)

        return wrapper

    return decorator
© www.soinside.com 2019 - 2024. All rights reserved.