关于python:使用类作为另一个类的方法的装饰器

Using class as decorator for another class's method

我对使用一个类来修饰另一个类的方法有一个问题。代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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() takes exactly 3 arguments (2 given).

如果使用调用

1
t.func(t, 1, 2)

然后就过去了。但是如果装饰器被拿走了,这条线就会再次出现问题。

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

edit:要在decorator.call中显示self的代码的第二个版本应与test.func中的self不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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()

这显示相同的错误。但是

1
t.func(t)

有效但不理想。


要作为一个方法工作,类中的对象需要实现描述符协议的一部分。也就是说,它应该有一个__get__方法,该方法返回一个已"绑定"到该方法所查找的实例的可调用对象。

下面是一种使用包装函数的方法:

1
2
3
4
5
6
7
8
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不会在描述符类之外工作)。