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.

+3


source to share


1 answer


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.

+3


source







All Articles