Search code examples
pythonpython-decorators

How to change a global parameter inside a decorator and automatically reset it?


I am trying to change a config dictionary inside the decorator (So I don't have to mess with the code of the function do_something() itself). I am experiencing problems however with 'resetting' the dictionary to its old state.

How do I do this? And is there a better way going forward than this approach (without changing the do_something() code itself)?

I've tried several approaches in regards to placement of the CONFIG variable, but in the end, the global context is never reset to the original state.

import copy

CONFIG = {
    'key': 'value'
}


def alter_dictionary_decorator(function):
    def wrapper():
        old = copy.deepcopy(CONFIG)
        CONFIG['key'] = 'other_value'
        func = function()
        config = old # <- can't put 'CONFIG = old' here
        return func
    return wrapper

@alter_dictionary_decorator
def do_something():
    print(CONFIG['key'])


if __name__ == '__main__':
    print(CONFIG['key'])
    do_something()
    print(CONFIG['key'])

Expected results = 'value', 'other_value', 'value'

Observerd results = 'value', 'other_value', 'other_value'


Solution

  • You need to use the global keyword in order to modify variables that have global scope. Also, config = old should have been CONFIG = old.

    The following code works as you require:

    import copy
    
    CONFIG = {
        'key': 'value'
    }
    
    
    def alter_dictionary_decorator(function):
        def wrapper():
            global CONFIG
            old = copy.deepcopy(CONFIG)
            CONFIG['key'] = 'other_value'
            func = function()
            CONFIG = old
            return func
        return wrapper
    
    @alter_dictionary_decorator
    def do_something():
        print(CONFIG['key'])
    
    
    if __name__ == '__main__':
        print(CONFIG['key'])
        do_something()
        print(CONFIG['key'])
    

    With the output being:

    value
    other_value
    value