Assume I have some simple class
class TestClass:
def doSomething(self):
print 'Did something'
I would like to decorate the doSomething method, for example to count the number of calls
class SimpleDecorator(object):
def __init__(self,func):
self.func=func
self.count=0
def __get__(self,obj,objtype=None):
return MethodType(self,obj,objtype)
def __call__(self,*args,**kwargs):
self.count+=1
return self.func(*args,**kwargs)
Now this counts the number of calls to the decorated method, however I would like to have per-instance counter, such that after
foo1=TestClass()
foo1.doSomething()
foo2=TestClass()
foo1.doSomething.count is 1 and foo2.doSomething.count is 0. From what I understand, this is not possible using decorators. Is there some way to achieve such behaviour?
解决方案
Utilize the fact that self (i.e. the object which the method is invoked on) is passed as a parameter to the method:
import functools
def counted(method):
@functools.wraps(method)
def wrapped(obj, *args, **kwargs):
if hasattr(obj, 'count'):
obj.count += 1
else:
obj.count = 1
return method(obj, *args, **kwargs)
return wrapped
In above code, we intercept the object as obj parameter of the decorated version of method. Usage of the decorator is pretty straightforward:
class Foo(object):
@counted
def do_something(self): pass