Context provider

A context provider decorator makes sure that the function can run in the correct context, or executes some code before and/or after executing a decorated function. In other words, it sets and unsets a specific execution environment. For example, when a data item has to be shared among several threads, a lock has to be used to ensure that it is protected from multiple access. This lock can be coded in a decorator as follows:

from threading import RLock 
lock = RLock() 
 
 
def synchronized(function): 
    def _synchronized(*args, **kw): 
        lock.acquire() 
        try: 
            return function(*args, **kw) 
        finally: 
            lock.release() 
    return _synchronized 
 
 
@synchronized 
def thread_safe():  # make sure it locks the resource 
    pass 

Context decorators are often being replaced by the usage of context managers (the with statement) which are also described later in this chapter.