Reputation: 167
Is possible to monkey patch the global variables?
For my case, I setup the a global variable to be the default logger of whole file, but for some special function I would use a decorator to change the logger and add some extra information.
Such as follow code:
libmonkey.py
logger = logging.getLogger(__name__)
@change_logger('import')
def do_some():
logger.debug('This is a debug')
#do some things
def do_some2():
logger.debug('This is a debug')
#do some things
decorator.py
def change_logger(name):
def decorator(func):
@functools.wraps(func)
def wrapper(*arg, **kwargs):
logger = logging.getLogger(name)
func(*arg, **kwargs)
return wrapper
return decorator
And when I do follow code, the log of do_some()
is not go to logger import
instead of libmonkey
from libmonkey import do_some, do_some2
#skip code for set logging lvl to debug, and output logging to stream.
do_some()
do_some2()
So how to use decorator to monkey patching the global variable.
Upvotes: 4
Views: 1134
Reputation: 1122322
You can alter the function globals temporarily:
_sentinel = object()
def change_logger(name):
def decorator(func):
@functools.wraps(func)
def wrapper(*arg, **kwargs):
old_logger = func.__globals__.get('logger', _sentinel)
func.__globals__['logger'] = logging.getLogger(name)
try:
result = func(*arg, **kwargs)
finally:
if old_logger is not _sentinel:
func.__globals__['logger'] = old_logger
else:
del func.__globals__['logger']
return result
return wrapper
return decorator
This is not thread safe; you are altering the globals not just for this function but for the whole module.
Upvotes: 4