Decorating decorators
At work, my friend Jon and I were looking into timing the various decorators in the app (bitbucket.org). We didn’t want to manually modify each decorator we were hoping to time. I ended up exploring the possibility of decorating decorators. It was an approach that could allow us to make the minimum modification to a decorator (just slapping on the timing decorator) and with very little duplicate code.
Here’s the basic approach:
import time
from functools import wraps
def timed(decorator):
def wrapped_decorator(func):
recorded_time = []
def timed(func):
@wraps(func)
def timed_func(*args, **kwargs):
start = time.time()
rv = func(*args, **kwargs)
if recorded_time:
outer_time = time.time() - start
print 'Decorator time: ', outer_time - recorded_time.pop()
else:
recorded_time.append(time.time() - start)
return rv
return timed_func
return timed(decorator(timed(func)))
return wrapped_decorator
@timed
def upper(func):
def wrapped():
time.sleep(1.3)
return func().upper()
return wrapped
@upper
def hello():
time.sleep(0.7)
return 'hello'
if __name__ == '__main__':
print hello()