Python decorators
This is the post about python decorators. I wanted to know what they are and I also wanted to write some decorators to profile my code and to record data.
Introduction
- Primer on Python Decorators
- What does functools.wraps do?
- Decorators and Wrappers in Python
- Common Gotchas
- Usage Ideas
- Multiple decorators
- Meta decorators
Some usages
Profiler
import logging
import time
from functools import wraps
def profiler(f):
"""
Logs the time a function takes to execute.
:param f: function
"""
@wraps(f)
def wrapper():
t1 = time.time()
f()
t2 = time.time()
time_taken = t2 - t1
logger = logging.getLogger(f.__module__)
log_message = f.__name__ + " took " + str(time_taken) + " secs"
if time_taken >= 3:
logger.warn(log_message)
else:
logger.debug(log_message)
return wrapper
Data recorder
import json
import logging
from functools import wraps
from logging.handlers import RotatingFileHandler
from config.logging import DATA_LOG_BASE_PATH
def record_data(f):
"""
Records input and output of an function.
:param f: function IO to record
"""
@wraps(f)
def wrapper(*args, **kwargs):
result = f(*args, **kwargs)
data = {'input': (args, kwargs), 'output': result}
_get_logger(f).info(json.dumps(data))
return result
return wrapper
def _get_logger(f):
# trying to get a logger with unique name so that no one else uses this loggger in normal code
logger = logging.getLogger(f.__module__ + "_" + f.__name__ + "_data")
# stopping propagation to parent logger so that only we should log it
logger.propagate = False
# 10 file of 10 mb
handler = RotatingFileHandler(DATA_LOG_BASE_PATH + "_" + f.__module__ + "_" + f.__name__ + "_data.log",
maxBytes=10485760, backupCount=10)
formatter = logging.Formatter(fmt='[%(asctime)s] [%(message)s]')
handler.setFormatter(formatter)
handler.setLevel(logging.INFO)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
return logger
## Other examples
There are many more use cases of decorators. May can be found here: