I am new to python decorators. I have understood the basic concepts with the help of simple examples. But when I tried to read this more practical decorator, I feel lost. Given below is the code followed by my questions:
class countcalls(object):
"Decorator that keeps track of the number of times a function is called."
__instances = {}
def __init__(self, f):
self.__f = f
self.__numcalls = 0
countcalls.__instances[f] = self
def __call__(self, *args, **kwargs):
self.__numcalls += 1
return self.__f(*args, **kwargs)
def count(self):
"Return the number of times the function f was called."
return countcalls.__instances[self.__f].__numcalls
@countcalls
def f():
print 'f called'
f()
f()
f()
print f.count() # prints 3
My doubts:
When we prefix the decorator to a function, does that mean that we are creating an object of the decorator class right there? In our case, when it says:
@countcalls
def f(): print 'f called'
Is @countcalls
equivalent to creating a countcalls
object and passing the function below to its __init__
method?
The
__call__
is taking three arguments.self
is fine as far as the question above is answered. What the hell are the two other arguments:*args, **kwargs
and what are they achieving?How can I get better at decorators?