2016-06-13 63 views
1

我想用一個裝飾做一些準備工作,並記錄狀態的功能也有,所以我寫類似的東西:類作爲裝飾類方法

class Decorator: 
    def __init__(self, func): 
     self.count = 0 
     self.func = func 

    def __call__(self, *args, **kwargs): 
     self.count += 1 # Simply count the call times 
     return self.func(self, *args, **kwargs) 

class Foo: 
    def __init__(self): 
     self.value = 0 

    @Decorator 
    def test(self, value): 
     self.value = value # change the value of instance 
     print(self.value) 

f = Foo() 
f.test(1) 

print(f.value) 
print(f.test.value) 

但很明顯,self__call__(self, *args, **kwargs)對應例如Decorator而不是Foo的實例,這將使f.value不變,但是f.test.value增加。

有沒有什麼辦法可以將Foo的實例傳遞給Decorator而不是Decorator本身?

還是有什麼辦法可以更清楚的實現這個功能嗎?

謝謝先進。

+0

什麼f.test.value辦? –

+0

我200%確定我沒有完全理解你的問題。就像在你的代碼中一樣,你想記錄一次調用@Decorator的方法的次數。這很好,但你以後如何訪問** count **。我試過一個例子,你可以將** Foo **的實例傳遞給** Decorator **,但是f.test.value不起作用 –

+0

你可以使用'f.test.count'訪問count,其中'f '是'Foo'的一個實例。 – Leon

回答

3

由於裝飾器只被調用一次,並將所有實例的方法替換爲裝飾器類的一個實例。它所做的就是:

Foo.test = Decorator(Foo.test) 

這使得它無法檢測稱爲實例。一個變通方法是手工應用在Foo__init__裝飾:

class Foo: 
    def __init__(self): 
     self.value = 0 
     self.test = Decorator(self.test) 

    def test(self, value): 
     self.value = value # change the value of instance 
     print(self.value) 

這樣的裝飾包裝的實例方法,這樣你就不會需要通過selfDecorator__call__

class Decorator: 
    def __init__(self, func): 
     self.count = 0 
     self.func = func 

    def __call__(self, *args, **kwargs): 
     self.count += 1 # Simply count the call times 
     return self.func(*args, **kwargs) 

現在,它的工作原理,你需要更新你的測試方法,如f.test.value不再存在:

f = Foo() 
f.test(1) 

print(f.value) 

按預期輸出1兩倍。

+0

upvote簡單:) –

0

我得到這個here

import functools 

class Decorator(object): 
    def __init__(self, func): 
     self.count = 0 
     self.func = func 


    def __call__(self, *args, **kwargs): 
     self.count += 1 # Simply count the call times 
     return self.func(*args, **kwargs) 

    def __get__(self, instance, instancetype): 
     """Implement the descriptor protocol to make decorating instance 
     method possible. 
     """ 

     # Return a partial function with the first argument is the instance 
     # of the class decorated. 
     return functools.partial(self.__call__, instance) 



class Foo: 
    def __init__(self): 
     self.value = 0 

    @Decorator 
    def test(self, value): 
     self.value = value # change the value of instance 



f = Foo() 
f.test(3) 
print(f.value) # prints 3 


g = Foo() 
g.test(8) 
print(g.value) # prints 8 

可能是這樣

def preJob(function): 
    def updateToDo(self, *args, **kwargs): 
     # do some recording 
     function(self, *args, **kwargs) 
    return updateToDo 

class Foo(object): 
    def __init__(self): 
     self.value = 0 

    @preJob 
    def test(self, value): 
     self.value = value 

f = Foo() 
f.test(3) 
print(f.value) # prints 3 


g = Foo() 
g.test(8) 
print(g.value) # prints 8