我正在寻找一个缓存装饰器,它给出一个函数将函数的结果缓存到装饰中指定的位置。像这样:
@cacheable('/path/to/cache/file')
def my_function(a, b, c):
return 'something'
装饰器的参数与它包装的函数的参数完全分开。我已经看了很多例子,但是我还没有完成如何做到这一点 - 是否有可能为装饰器提供一个与包装函数无关且不传递给包装函数的参数?
答案 0 :(得分:9)
这个想法是你的装饰器是一个返回装饰器的函数。
第一次写你的装饰者,好像你知道你的论证是一个全局变量。我们这样说:
-
def decorator(f):
def decorated(*args,**kwargs):
cache = Cache(cachepath)
if cache.iscached(*args,**kwargs):
...
else:
res = f(*args,**kwargs)
cache.store((*args,**kwargs), res)
return res
return decorated
THEN 编写一个将cachepath作为arg并返回装饰器的函数。
-
def cache(filepath)
def decorator(f):
def decorated(*args,**kwargs):
cache = Cache(cachepath)
if cache.iscached(*args,**kwargs):
...
else:
res = f(*args,**kwargs)
cache.store((*args,**kwargs), res)
return res
return decorated
return decorator
答案 1 :(得分:5)
是的。如您所知,装饰器是一种功能。写在表格中时:
def mydecorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@mydecorator
def foo(a, b, c):
pass
传递给mydecorator
的参数是函数foo
本身。
当装饰器接受参数时,调用@mydecorator('/path/to')
实际上将首先使用'/ path / to'调用mydecorator函数。然后将调用mydecorator(path)
调用的结果来接收函数foo
。您正在有效地定义动态包装函数。
简而言之,您需要另一层装饰器功能。
这是一个有点愚蠢的例子:
def addint(val):
def decorator(func):
def wrapped(*args, **kwargs):
result = func(*args, **kwargs)
return result + val
return wrapped # returns the decorated function "add_together"
return decorator # returns the definition of the decorator "addint"
# specifically built to return an extra 5 to the sum
@addint(5)
def add_together(a, b):
return a + b
print add_together(1, 2)
# prints 8, not 3
答案 2 :(得分:3)
Paul的答案很好,我会移动缓存对象,因此不需要每次都构建它,并设计缓存,以便在缓存未命中时引发KeyError:
def cache(filepath): def decorator(f): f._cache = Cache(cachepath) def decorated(*args,**kwargs): try: key = (args, kwargs) res = f._cache.get(key) except KeyError: res = f(*args, **kwargs) f._cache.put(key, res) return res return decorated return decorator