考虑以下几点:
@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,真正的计算不依赖于可变值
当前回答
从Python 3.2开始,有一个内置的装饰器:
@functools。lru_cache(最大容量= 100,输入= False)
装饰器使用一个可记忆可调用对象来包装函数,该可调用对象最多保存maxsize最近的调用。当使用相同的参数周期性地调用昂贵的或I/O绑定的函数时,它可以节省时间。
用于计算斐波那契数的LRU缓存示例:
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
>>> print([fib(n) for n in range(16)])
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
>>> print(fib.cache_info())
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
如果你被Python 2困住了。X,这里是其他兼容的内存库列表:
functools32 | PyPI |源代码 repoze。lru | PyPI |源代码 pylru | PyPI |源代码 补丁。functools_lru_cache | PyPI |源代码
其他回答
Python 3.8 functools。cached_property装饰
https://docs.python.org/dev/library/functools.html#functools.cached_property
来自Werkzeug的cached_property在:https://stackoverflow.com/a/5295190/895245上提到过,但据说派生版本将合并到3.8中,这是非常棒的。
这个装饰器可以被看作是缓存@property,或者是清洁器@functools。Lru_cache,当你没有任何参数时。
医生说:
@functools.cached_property(func) Transform a method of a class into a property whose value is computed once and then cached as a normal attribute for the life of the instance. Similar to property(), with the addition of caching. Useful for expensive computed properties of instances that are otherwise effectively immutable. Example: class DataSet: def __init__(self, sequence_of_numbers): self._data = sequence_of_numbers @cached_property def stdev(self): return statistics.stdev(self._data) @cached_property def variance(self): return statistics.variance(self._data) New in version 3.8. Note This decorator requires that the dict attribute on each instance be a mutable mapping. This means it will not work with some types, such as metaclasses (since the dict attributes on type instances are read-only proxies for the class namespace), and those that specify slots without including dict as one of the defined slots (as such classes don’t provide a dict attribute at all).
从Python 3.2开始,有一个内置的装饰器:
@functools。lru_cache(最大容量= 100,输入= False)
装饰器使用一个可记忆可调用对象来包装函数,该可调用对象最多保存maxsize最近的调用。当使用相同的参数周期性地调用昂贵的或I/O绑定的函数时,它可以节省时间。
用于计算斐波那契数的LRU缓存示例:
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
>>> print([fib(n) for n in range(16)])
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
>>> print(fib.cache_info())
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
如果你被Python 2困住了。X,这里是其他兼容的内存库列表:
functools32 | PyPI |源代码 repoze。lru | PyPI |源代码 pylru | PyPI |源代码 补丁。functools_lru_cache | PyPI |源代码
尝试joblib https://joblib.readthedocs.io/en/latest/memory.html
from joblib import Memory
memory = Memory(cachedir=cachedir, verbose=0)
@memory.cache
def f(x):
print('Running f(%s)' % x)
return x
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 functools import wraps
def cache(maxsize=128):
cache = {}
def decorator(func):
@wraps(func)
def inner(*args, no_cache=False, **kwargs):
if no_cache:
return func(*args, **kwargs)
key_base = "_".join(str(x) for x in args)
key_end = "_".join(f"{k}:{v}" for k, v in kwargs.items())
key = f"{key_base}-{key_end}"
if key in cache:
return cache[key]
res = func(*args, **kwargs)
if len(cache) > maxsize:
del cache[list(cache.keys())[0]]
cache[key] = res
return res
return inner
return decorator
def async_cache(maxsize=128):
cache = {}
def decorator(func):
@wraps(func)
async def inner(*args, no_cache=False, **kwargs):
if no_cache:
return await func(*args, **kwargs)
key_base = "_".join(str(x) for x in args)
key_end = "_".join(f"{k}:{v}" for k, v in kwargs.items())
key = f"{key_base}-{key_end}"
if key in cache:
return cache[key]
res = await func(*args, **kwargs)
if len(cache) > maxsize:
del cache[list(cache.keys())[0]]
cache[key] = res
return res
return inner
return decorator
示例使用
import asyncio
import aiohttp
# Removes the aiohttp ClientSession instance warning.
class HTTPSession(aiohttp.ClientSession):
""" Abstract class for aiohttp. """
def __init__(self, loop=None) -> None:
super().__init__(loop=loop or asyncio.get_event_loop())
def __del__(self) -> None:
if not self.closed:
self.loop.run_until_complete(self.close())
self.loop.close()
return
session = HTTPSession()
@async_cache()
async def query(url, method="get", res_method="text", *args, **kwargs):
async with getattr(session, method.lower())(url, *args, **kwargs) as res:
return await getattr(res, res_method)()
async def get(url, *args, **kwargs):
return await query(url, "get", *args, **kwargs)
async def post(url, *args, **kwargs):
return await query(url, "post", *args, **kwargs)
async def delete(url, *args, **kwargs):
return await query(url, "delete", *args, **kwargs)