考虑以下几点:
@property
def name(self):
if not hasattr(self, '_name'):
# expensive calculation
self._name = 1 + 1
return self._name
我是新来的,但我认为缓存可以分解成一个装饰器。只是我没有找到一个这样的;)
PS,真正的计算不依赖于可变值
考虑以下几点:
@property
def name(self):
if not hasattr(self, '_name'):
# expensive calculation
self._name = 1 + 1
return self._name
我是新来的,但我认为缓存可以分解成一个装饰器。只是我没有找到一个这样的;)
PS,真正的计算不依赖于可变值
当前回答
Werkzeug有一个cached_property装饰器(docs, source)
其他回答
class memorize(dict):
def __init__(self, func):
self.func = func
def __call__(self, *args):
return self[args]
def __missing__(self, key):
result = self[key] = self.func(*key)
return result
示例使用:
>>> @memorize
... def foo(a, b):
... return a * b
>>> foo(2, 4)
8
>>> foo
{(2, 4): 8}
>>> foo('hi', 3)
'hihihi'
>>> foo
{(2, 4): 8, ('hi', 3): 'hihihi'}
创建自己的装饰器并使用它
from django.core.cache import cache
import functools
def cache_returned_values(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
key = "choose a unique key here"
results = cache.get(key)
if not results:
results = func(*args, **kwargs)
cache.set(key, results)
return results
return wrapper
现在看函数
@cache_returned_values
def get_some_values(args):
return x
@lru_cache不适合默认attrs
我的@mem装饰:
import inspect
from copy import deepcopy
from functools import lru_cache, wraps
from typing import Any, Callable, Dict, Iterable
# helper
def get_all_kwargs_values(f: Callable, kwargs: Dict[str, Any]) -> Iterable[Any]:
default_kwargs = {
k: v.default
for k, v in inspect.signature(f).parameters.items()
if v.default is not inspect.Parameter.empty
}
all_kwargs = deepcopy(default_kwargs)
all_kwargs.update(kwargs)
for key in sorted(all_kwargs.keys()):
yield all_kwargs[key]
# the best decorator
def mem(func: Callable) -> Callable:
cache = dict()
@wraps(func)
def wrapper(*args, **kwargs) -> Any:
all_kwargs_values = get_all_kwargs_values(func, kwargs)
params = (*args, *all_kwargs_values)
_hash = hash(params)
if _hash not in cache:
cache[_hash] = func(*args, **kwargs)
return cache[_hash]
return wrapper
# some logic
def counter(*args) -> int:
print(f'* not_cached:', end='\t')
return sum(args)
@mem
def check_mem(a, *args, z=10) -> int:
return counter(a, *args, z)
@lru_cache
def check_lru(a, *args, z=10) -> int:
return counter(a, *args, z)
def test(func) -> None:
print(f'\nTest {func.__name__}:')
print('*', func(1, 2, 3, 4, 5))
print('*', func(1, 2, 3, 4, 5))
print('*', func(1, 2, 3, 4, 5, z=6))
print('*', func(1, 2, 3, 4, 5, z=6))
print('*', func(1))
print('*', func(1, z=10))
def main():
test(check_mem)
test(check_lru)
if __name__ == '__main__':
main()
输出:
Test check_mem:
* not_cached: * 25
* 25
* not_cached: * 21
* 21
* not_cached: * 11
* 11
Test check_lru:
* not_cached: * 25
* 25
* not_cached: * 21
* 21
* not_cached: * 11
* not_cached: * 11
如果你正在使用Django框架,它有这样一个属性来缓存API的视图或响应 使用@cache_page(time),也可以有其他选项。
例子:
@cache_page(60 * 15, cache="special_cache")
def my_view(request):
...
更多细节可以在这里找到。
fastcache,这是Python 3 functools.lru_cache的C实现。提供10-30倍于标准库的加速。”
和选择的答案一样,只是导入不同:
from fastcache import lru_cache
@lru_cache(maxsize=128, typed=False)
def f(a, b):
pass
此外,它安装在Anaconda中,不像functools需要安装。