使用类作为另一个类的方法的装饰器

时间:2018-03-07 01:34:21

标签: python class methods decorator

我在使用类来装饰另一个类的方法时遇到了问题。代码如下

class decorator(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args):
        return self.func(*args)

class test(object):
    @decorator
    def func(self, x, y):
        print x, y

t = test()
t.func(1, 2)

显示此错误

  

TypeError:func()只需要3个参数(给定2个)。

如果使用

调用
t.func(t, 1, 2)
然后它通过了。但是如果装饰器被带走,那么这条线将再次出现问题。

为什么会发生这种情况以及如何解决?

编辑:在装饰器中显示自我的代码的第二个版本。调用应该与test.func中的self不同

class decorator(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args):
        return self.func(*args)

class test(object):
    def __init__(self):
        self.x = 1
        self.y = 2
    @decorator
    def func(self):
        print self
        print self.x, self.y

t = test()
t.func()

这显示了同样的错误。但是

t.func(t)

有效但不理想。

1 个答案:

答案 0 :(得分:2)

要作为方法工作,类中的对象需要实现the descriptor protocol的一部分。也就是说,它应该有一个__get__方法,它返回一个可调用的对象,该对象已被“绑定”到查找该方法的实例。

这是使用包装函数实现这一目标的一种方法:

class decorator(object):
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        def wrapper(*args):
            return self.func(instance, *args) # note, self here is the descriptor object
        return wrapper

您可以从__get__而不是函数返回其他类的实例,并使用该其他类的__call__方法来实现包装器。如果您没有使用闭包,则需要将instance显式传递给包装类(以及函数,因为self.func将无法在描述符类之外工作)。