2011-07-07 187 views
2

考慮下面來裝飾裝飾器是不同於裝飾器的功能類嗎?

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(kwargs)) 
     func(*args,**kwargs) 
    return wrapped_func 

他們期待着做同樣的,和功能這是真的:

@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") 

打印:

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

對於方法然而,有些東西很奇怪的事情發生:

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") 

打印:

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) 

沒有太多的期待!不知何故,TestClass對象不會作爲參數傳遞給裝飾器對象的__call__方法。

爲什麼這種差異?還有,我仍然可以在我的類風格裝飾器中獲取對象嗎?

回答

2

self被綁定到實例方法的第一個參數只能工作,因爲方法被包裝在descriptors中。當obj.meth被請求時,在對象中找不到,然後在類中找到,描述符的__get__方法被調用時包含該對象的一些信息,並且返回一個包裹實際方法對象的方法,當被調用時,調用底層方法作爲附加/第一個參數的對象(self)。

這些描述符僅用於實際功能,而不用於其他可調用對象。要使一個__call__方法的類與方法一樣工作,您必須實現一個__get__方法(請參閱上面的鏈接)。