Existen dos formas de hacerlo. La forma orientada a objetos es hacer una clase:
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
Ver this question para una explicación de wraps
.
Prefiero el enfoque OOP anterior para este tipo de decorador, ya que básicamente tiene una variable de conteo privada que rastrea el número de ejecuciones. Sin embargo, el otro enfoque es utilizar un cierre, como
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
Esto implicaba tres funciones. A la función max_execs
se le asigna un parámetro para el número de ejecuciones y devuelve un decorador que lo restringirá a esa cantidad de llamadas. Esa función, actual_decorator
, hace lo mismo que nuestro método __call__
en el ejemplo OOP. La única rareza es que, dado que no tenemos una clase con variables privadas, tenemos que mutar la variable executions
que se encuentra en el ámbito externo de nuestro cierre. Python 3.0 admite esto con la instrucción nonlocal
, pero en Python 2.6 o anterior, necesitamos ajustar el número de ejecuciones en una lista para que pueda mutarse.
al aplicar este decorador, ¿cómo se "traduce" el código por python? Por ejemplo, si mi método se llama blabla, y aplico el atributo max_execs, ¿cómo lo verá Python? blabla = max_execs (5) (blabla)? – Geo
Actualicé la respuesta para incluir la traducción, pero tiene la idea correcta. – mipadi