带参数的装饰器包裹类方法的问题

0 投票
1 回答
1353 浏览
提问于 2025-04-18 17:22

我正在尝试写一个带参数的装饰器,用来包装某个特定类的方法。我试过用函数装饰器和类装饰器,但都遇到了不同的错误。尝试调整参数的签名也没有帮助。

示例用法

class X(object):
    def __init__():
        self.a = True
        self.b = ""

    @my_deco([])
    def xfunc(self, x, y):
        do stuff...

foo = X()
foo.xfunc()

函数装饰器:

def my_deco(param1):
    def wrapped(func):
        def wrapped_f(self, *args, **kwargs):
            try:
                self.a = True
                return func(self, *args, **kwargs)
            except Exception as e:
                self.b = str(e)
                self.a = False
                return param1
        return wrapped_f
    return wrapped

出现这个错误:TypeError: wrapped() 需要 1 个参数(给了 3 个)

类装饰器:

class my_deco(object):

    def __init__(self, param1=False):
        self.param1 = param1

    def __call__(self, f):

        @wraps(f)
        def wrapped_f(self, *args, **kwargs):
            try:
                self.a = True
                return f(self, *args, **kwargs)
            except Exception as e:
                self.b = str(e)
                self.a = False
                return self.param1
        return wrapped_f
    #
    #def __get__(self, obj, objtype):
    #    """Support instance methods."""
    #    import functools
    #    return functools.partial(self.__call__, obj)

出现这个错误:TypeError: call() 需要 2 个参数(给了 3 个)

有没有什么线索可以帮助我解决这个问题?

1 个回答

1

在我尝试写出可以运行的代码作为示例时,我发现了自己的错误。可能是在写包装器的时候搞混了,导致我在让它工作时忽略了一个简单的错误。

下面是一个可以正常工作的例子。我犯的错误是没有给我正在测试的方法的装饰器传递参数,这就导致了异常。这解释了问题,因为装饰器是期待有一个参数的。

def my_deco(param1):
    def wrapped(func):
        def wrapped_f(self, *args, **kwargs):
            try:
                self.a = True
                return func(self, *args, **kwargs)
            except Exception as e:
                self.b = str(e)
                self.a = False
                return param1
        return wrapped_f
    return wrapped

class Base(object):
    def __init__(self, attr1, attr2):
        self.attr1 = attr1
        self.attr2 = attr2
        self.a = False
        self.b = ""

    @my_deco([])
    def xfunc(self, x, y):
        return x + y

def ClassFactory(attr1, attr2, base=Base):
    class NewClass(Base):
        def __init__(self):
            super(NewClass, self).__init__(attr1, attr2)

    return NewClass

ChildClass = ClassFactory("foo", "bar")
child = ChildClass()

print child.xfunc(1, 2) # no exception
print child.xfunc('x', 2) # throws exception

撰写回答