There are two ways of doing it. The object-oriented way is to make a class:
class max_execs:
def __init__(self, max_executions):
self.max_executions = max_executions
self.executions = 0
def __call__(self, func):
@wraps(func)
def maybe(*args, **kwargs):
if self.executions < self.max_executions:
self.executions += 1
return func(*args, **kwargs)
else:
print "fail"
return maybe
See this question for an explanation of wraps
.
I prefer the above OOP approach for this kind of decorator, since you've basically got a private count variable tracking the number of executions. However, the other approach is to use a closure, such as
def max_execs(max_executions):
executions = [0]
def actual_decorator(func):
@wraps(func)
def maybe(*args, **kwargs):
if executions[0] < max_executions:
executions[0] += 1
return func(*args, **kwargs)
else:
print "fail"
return maybe
return actual_decorator
This involved three functions. The max_execs
function is given a parameter for the number of executions and returns a decorator that will restrict you to that many calls. That function, the actual_decorator
, does the same thing as our __call__
method in the OOP example. The only weirdness is that since we don't have a class with private variables, we need to mutate the executions
variable which is in the outer scope of our closure. Python 3.0 supports this with the nonlocal
statement, but in Python 2.6 or earlier, we need to wrap our executions count in a list so that it can be mutated.