loop - sentencias en python
Cómo hacer un decorador condicional en Python. (6)
¿Es posible decorar una función condicionalmente? Por ejemplo, quiero decorar la función foo()
con una función de temporizador ( timeit
), haciendo que el análisis de rendimiento es True
(consulte el código psuedo a continuación).
if doing_performance_analysis:
@timeit
def foo():
"""
do something, timeit function will return the time it takes
"""
time.sleep(2)
else:
def foo():
time.sleep(2)
Esto es lo que funcionó para mí:
def timeit(method):
def timed(*args, **kw):
if ''usetimer'' not in kw:
return method(*args, **kw)
elif (''usetimer'' in kw and kw.get(''usetimer'') is None):
return method(*args, **kw)
else:
import time
ts = time.time()
result = method(*args, **kw)
te = time.time()
if ''log_time'' in kw:
name = kw.get(''log_name'', method.__name__.upper())
kw[''log_time''][name] = int((te - ts) * 1000)
else:
print ''%r took %2.2f ms'' % /
(method.__name__, (te - ts) * 1000)
return result
return timed
def some_func(arg1, **kwargs):
#do something here
some_func(param1, **{''usetimer'': args.usetimer})
La respuesta de Blckknght es excelente si desea realizar la comprobación cada vez que llama a la función, pero si tiene una configuración que puede leer una vez y nunca cambia, es posible que no quiera verificarla cada vez que se llame a la función decorada. En algunos de nuestros demonios de alto rendimiento en el trabajo, he escrito un decorador que comprueba un archivo de configuración una vez que el archivo de Python se carga por primera vez y decide si debe envolverlo o no.
Aquí hay una muestra.
def timed(f):
def wrapper(*args, **kwargs):
start = datetime.datetime.utcnow()
return_value = f(*args, **kwargs)
end = datetime.datetime.utcnow()
duration = end - start
log_function_call(module=f.__module__, function=f.__name__, start=__start__, end=__end__, duration=duration.total_seconds())
if config.get(''RUN_TIMED_FUNCTIONS''):
return wrapper
return f
Suponiendo que log_function_call registra su llamada a una base de datos, archivo de registro o lo que sea y que config.get (''RUN_TIMED_FUNCTIONS'') verifica su configuración global, luego agregar el decorador @timed a una función comprobará una vez en la carga para ver si está sincronizando este servidor, entorno, etc., y si no, no cambiará la ejecución de la función en producción o en otros entornos en los que se preocupe por el rendimiento.
Los decoradores son simplemente callables que devuelven un reemplazo, opcionalmente la misma función, una envoltura o algo completamente diferente. Como tal, podrías crear un decorador condicional:
def conditional_decorator(dec, condition):
def decorator(func):
if not condition:
# Return the function unchanged, not decorated.
return func
return dec(func)
return decorator
Ahora puedes usarlo así:
@conditional_decorator(timeit, doing_performance_analysis)
def foo():
time.sleep(2)
El decorador también podría ser una clase:
class conditional_decorator(object):
def __init__(self, dec, condition):
self.decorator = dec
self.condition = condition
def __call__(self, func):
if not self.condition:
# Return the function unchanged, not decorated.
return func
return self.decorator(func)
Aquí, el método __call__
desempeña el mismo papel que la función anidada decorator()
devuelta en el primer ejemplo, y los parámetros dec
y sobre cerrados en este caso se almacenan como argumentos en la instancia hasta que se aplica el decorador.
Qué tal si:
def foo():
...
if doing_performance_analysis:
foo = timeit(foo)
Me imagino que incluso podría envolver esto en un decorador que tomaría una bandera booleana y otro decorador, y solo aplicaría este último si la bandera está establecida en True
:
def cond_decorator(flag, dec):
def decorate(fn):
return dec(fn) if flag else fn
return decorate
@cond_decorator(doing_performance_analysis, timeit)
def foo():
...
Un decorador es simplemente una función aplicada a otra función. Puedes aplicarlo manualmente:
def foo():
# whatever
time.sleep(2)
if doing_performance_analysis:
foo = timeit(foo)
use_decorator = False
class myDecorator(object):
def __init__(self, f):
self.f = f
def __call__(self):
print "Decorated running..."
print "Entering", self.f.__name__
self.f()
print "Exited", self.f.__name__
def null(a):
return a
if use_decorator == False :
myDecorator = null
@myDecorator
def CoreFunction():
print "Core Function running"
CoreFunction()