The function that I want to cache is something like:
def a(x, time='last'):
I have deterministic behaviour for every a(x,y)
, except when y=='last'
. So when a(x, 'last')
is called, I would like to call the "real thing" and an lru_cached function for everything else.
I imagine this could be possible with my own decorator:
def my_lru_cache(func):
def function_wrapper(*args, **kwargs):
if kwargs is not None:
if 'time' in kwargs:
return func(*args, **kwargs)
else:
return what?!?
return function_wrapper
Am I completely wrong? How could this be done?
Wrap the function in lru_cache()
, then add your decorator on top and access the original uncached function via the __wrapped__
attribute, or better still, use the inspect.unwrap()
function to strip the function of an arbitrary number of decorators:
from functools import wraps
from inspect import unwrap
def bypass_cache_last_time(func):
@wraps(func)
def function_wrapper(*args, **kwargs):
if not 'time' in kwargs or kwargs['time'] == 'last':
# Bypass any additional decorators and call function directly
return unwrap(func)(*args, **kwargs)
else:
return func(*args, **kwargs)
return function_wrapper
and use this as
@bypass_cache_last_time
@lru_cache()
def some_function(x, time='last'):
# ...
The functools.wraps()
decorator passes the ability to unwrap the decorator again forward, as it sets the __wrapped__
attribute on the wrapper.
Or make your decorator apply the lru_cache()
decorator itself and retain your own copy of the original function when decorating:
def my_lru_cache(func):
cached = lru_cache()(func)
@wraps(func)
def function_wrapper(*args, **kwargs):
if not 'time' in kwargs or kwargs['time'] == 'last':
# call the function directly
return func(*args, **kwargs)
else:
# use the lru_cache-wrapped version
return cached(*args, **kwargs)
return function_wrapper
use this as
@my_lru_cache
def some_function(x, time='last'):
# ...