开发者

Are decorators that are classes called different than decorators that are functions?

Consider the following to decorators

class MethodDecoratorC(object):
    def __init__(self,func):
        self.func = func
    def __call__(self,*args,**kwargs):
        print(len(args))
        print(len(kwargs))
        self.func(*args,**kwargs)

def method_decorator_f(func):
    def wrapped_func(*args,**kwargs):
        print(len(args))
        print(len(kw开发者_JS百科args))
        func(*args,**kwargs)
    return wrapped_func

They look to do exactly the same, and for functions that's true:

@MethodDecoratorC
def test_method_c(a):
    print(a)

@method_decorator_f
def test_method_f(a):
    print(a)

test_method_f("Hello World! f")
test_method_c("Hello World! c")

prints:

1
0
Hello World! f
1
0
Hello World! c

For methods however, something very strange happens:

class TestClass(object):
    @MethodDecoratorC
    def test_method_c(self,a):
        print(a)

    @method_decorator_f
    def test_method_f(self,a):
        print(a)

t = TestClass()
t.test_method_f("Hello World! f")
t.test_method_c("Hello World! c")

prints:

2
0
Hello World! f
1
0
Traceback (most recent call last):
  File "test5.py", line 40, in <module>
    t.test_method_c("Hello World! c")
  File "test5.py", line 8, in __call__
    self.func(*args,**kwargs)
TypeError: test_method_c() takes exactly 2 arguments (1 given)

Not much expected! Somehow the TestClass object is not transferred as an argument to the __call__ method of my decorator object.

Why this difference? And is there a way that I can still obtain the object in my class style decorator?


self being bound to the first argument for instance methods works only because methods are wrapped in descriptors. When obj.meth is requested, not found in the object and then found in the class, the descriptor's __get__ method is called with some information including the object, and returns a wrapper around the actual method object that, when called, calls the underlying method with the object as additonal/first argument (self).

These descriptors are only added for actual functions, not for other callable objects. To make a class with a __call__ method work like a method, you'll have to implement a __get__ method (see link above).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜