2016-06-13 88 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