Can a decorator be used to monkey patch global variables?
Is it possible for a monkey to pay with global variables?
In my case, I am setting a global variable as the default logger for the entire file, but for some special function, I would use a decorator to change the logger and add more information.
Such as the following 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 execute the code, the log do_some()
doesn't go to logger import
insteadlibmonkey
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 the monkey decorator while fixing the global variable.
source to share
You can temporarily change the global functions of the function:
_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 safety; you change global values not only for this function, but for the whole module.
source to share