def access_cache(self, key=None, key_location_on_param=<NUM_LIT:0>, expire=None, auto_update=True,<EOL>cache_loader=None, cache_writer=None, timeout=<NUM_LIT:1>):
def decorate(func):<EOL><INDENT>@functools.wraps(func)<EOL>def wrapper(*args, **kwargs):<EOL><INDENT>k = None<EOL>if len(args) - <NUM_LIT:1> >= key_location_on_param:<EOL><INDENT>k = args[key_location_on_param]<EOL><DEDENT>if key is not None:<EOL><INDENT>k = key<EOL><DEDENT>cache_result = self.get(key=k, timeout=timeout)<EOL>if cache_result is None:<EOL><INDENT>if cache_loader is not None:<EOL><INDENT>cache_result = cache_loader(k)<EOL><DEDENT>elif self.cache_loader is not None:<EOL><INDENT>cache_result = self.cache_loader(k)<EOL><DEDENT><DEDENT>if cache_result is not None:<EOL><INDENT>return cache_result<EOL><DEDENT>else:<EOL><INDENT>result = func(*args, **kwargs)<EOL><DEDENT>if auto_update:<EOL><INDENT>self.put(key=k, value=result, expire=expire, timeout=timeout)<EOL>if cache_writer is not None:<EOL><INDENT>self.thread_pool.submit(cache_writer, k, result)<EOL><DEDENT>elif self.cache_writer is not None:<EOL><INDENT>self.thread_pool.submit(self.cache_writer, k, result)<EOL><DEDENT><DEDENT>return result<EOL><DEDENT>return wrapper<EOL><DEDENT>return decorate<EOL>
The decorator for simplifying of use cache, it supports auto-update
cache(if parameter auto_update is True), load cache from other level cache
system or data source and writes back the update result to the
other level cache system or data source if cache miss.

The parameter key assigns a key for access cache or update cache and
if it is None so select a parameter as a key from the decorated function
by key_location_on_param, notice: key and key_location_on_param cannot all is None.

For function cache_loader() must is a one-parameter function and the parameter
represent a key of the cache, if this parameter is None so use self.cache_loader(),
if they all are None so not load cache from other caches system.

For function cache_writer() must is a two-parameter function and the first parameter
representing a key of the cache and the second parameter representing a value of the cache,
notice: if the parameter auto_update is False so it will not execute.

>>> import time
>>> cache = Cache(log_level=logging.WARNING)
>>> @cache.access_cache(key='a')
... def a():
...     return 'a from data source'
>>> a()
'a from data source'
>>> cache.get('a')
'a from data source'
>>> cache.put(key='b', value='b from cache')
>>> @cache.access_cache(key='b')
... def b():
...     return 'b from data source'
>>> b()
'b from cache'
>>> c_key = 'c'
>>> @cache.access_cache(key_location_on_param=0)
... def c(key):
...     return 'c from data source'
>>> c(c_key)
'c from data source'
>>> cache.get(c_key)
'c from data source'
>>> @cache.access_cache(key='d', auto_update=False)
... def d():
...     return 'd from data source'
>>> d()
'd from data source'
>>> cache.get('d') == None
True
>>> @cache.access_cache(key='e', cache_loader=lambda k: '%s from cache loader' % k)
... def e():
...     return 'e from data source'
>>> e()
'e from cache loader'
>>> out_dict = {}
>>> def writer(k, v):
...     out_dict[k] = v
>>> @cache.access_cache(key='f', cache_writer=writer)
... def f():
...     return 'f from data source'
>>> f()
'f from data source'
>>> time.sleep(1) # wait to execute complete because it in the other thread
>>> out_dict
{'f': 'f from data source'}
>>> cache.with_cache_loader(lambda k: '%s from cache loader(global)' % k)
True
>>> @cache.access_cache(key='g')
... def g():
...     return 'g from data source'
>>> g()
'g from cache loader(global)'