I am trying to make a decorator that when DEBUG == True, it does not cache, but when DEBUG == False, then it does cache.
This is what I came up with. It works in the case when DEBUG == False. The issue is when DEBUG == True:
from functools import lru_cache
DEBUG = True
def prod_lru_cache(*args, **kwargs):
def no_decorator(func):
return func
if DEBUG:
return no_decorator
else:
return prod_lru_cache(*args, **kwargs)
The issue is that lru_cache can take an optional argument maxsize.
If it takes no arguments, then I think the above is fine, e.g. We get back the original function as required when DEBUG == False:
DEBUG = False
@prod_lru_cache
def foo():
print('foo')
# prod_lru_cache(foo) -> (return no_decorator) -> (return foo) -> foo
However if it does take an argument, then it does no work:
DEBUG = False
@prod_lru_cache(maxsize=7)
def foo():
print('foo')
# prod_lru_cache(maxsize=7)(foo) -> (return no_decorator)(foo) -> (foo)foo -> ????
How does one handle both scenarios? I can't think of a way to distinguish between the passed in user function, and an arg (which in some cases could be a callable), in this example it should always be an int, but I would like to apply the same concept to other decorators.
A hack solution I came up with is:
def prod_cache(*args, **kwargs):
def no_decorator(f):
return f
if settings.DEBUG:
return args[0] if args and callable(args[0]) else no_decorator
else:
return cache(*args, **kwargs)
But it is not generic in that what if I wish to make a decorator with an arg that is a callable, then I can't apply the same logic.