我试图在lru_cache
中使用Python3来加速对Salesforce数据库的常见查询。下面是相关代码,应该是
当我尝试这段代码时,缓存用于调用没有参数的函数,但它似乎不缓存带有参数的函数调用。另外,我也不知道如何为装饰的功能定购装饰师。
注意,我在这里使用了一个类以及类和静态方法,这样我就可以为不同的get
子类重写Resource
和get_all
方法。
请解释我做错了什么或可能做得更好。
from functools import lru_cache
from functools import wraps
class Resource(object):
def hash_dict(func):
"""Transform mutable dictionnary
Into immutable
Useful to be compatible with cache
"""
class HDict(dict):
def __hash__(self):
return hash(frozenset(self.items()))
@wraps(func)
def wrapped(*args, **kwargs):
args = tuple([HDict(arg) if isinstance(arg, dict) else arg for arg in args])
kwargs = {}
for k, v in kwargs.items():
if isinstance(v, dict):
kwargs[k] = HDict(v)
elif isinstance(v, list):
kwargs[k] = tuple(v)
else:
kwargs[k] = v
return func(*args, **kwargs)
return wrapped
@staticmethod
@hash_dict
@lru_cache
def get(cls, resource_id, lang='en', fields=None):
pass
@classmethod
@hash_dict
@lru_cache
def get_all(cls, lang='en', filters=None, fields=None):
pass
发布于 2020-06-27 01:40:03
不需要额外的包裹。预期的下列工作:
import functools
class A:
@staticmethod
@functools.lru_cache(maxsize=None)
def build(value):
print('Creating', value)
return A()
assert A.build('a') is A.build('a')
assert A.build('b') is A.build('b')
assert A.build('b') is not A.build('a')
从python3.9开始,您可以用@functools.lru_cache(maxsize=None)
代替@functools.cache
。
发布于 2018-10-15 05:32:40
这应该是您正在寻找的答案:https://ring-cache.readthedocs.io/en/latest/quickstart.html#method-classmethod-staticmethod
lru_cache
只支持简单的函数。Ring
提供了非常相似的接口,但包含任何类型的描述符支持。
class Page(object):
(...)
@ring.lru()
@classmethod
def class_content(cls):
return cls.base_content
@ring.lru()
@staticmethod
def example_dot_com():
return requests.get('http://example.com').content
有关详细信息,请参阅链接。请注意,示例不是LRU。
发布于 2018-10-12 09:33:44
如果我为你来晚了,那就走吧,因为这是我的回应。你搞错了几件事。
首先,在args
函数定义中覆盖wapped
和kwargs
。这有效地删除了您的函数参数。
其次,您只在kwargs
中生成不可变的列表,而不是在args
中。
而且,lru_cache
是一个装饰构造函数,所以它必须被称为@lru_cache()
。我不知道没有它对你有什么用。
此外,您将def get(cls, ...
函数声明为@staticmethod
,那么它将不会收到cls
参数。
但是--最重要的是,--在类中定义一个装饰器并不像这篇媒体文章中所说的那样简单。我明白了您想要做的事情:通过继承强制缓存,虽然这看起来是个好主意,但它不能正常工作。如果您重写一个函数,您将不得不再次用缓存重新装饰它,这就忽略了在类中声明装饰器的意义。
为了结束它,我会省去自己的问题,在一个不同的类中声明装饰器,并在其他地方使用它。但是要小心,因为缓存类方法也不是简单的。
额外:
几周前,我也遇到过类似的情况,我想要缓存一个接受numpy数组的函数。我想出了基于这一实现的这是如此的反应。我只需将数组转换为元组,并再次重构它(因为我需要它在末尾是一个可变数组)。
def np_cache(*args, **kwargs):
"""LRU cache implementation for functions whose FIRST parameter is a numpy array
>>> array = np.array([[1, 2, 3], [4, 5, 6]])
>>> @np_cache(maxsize=256)
... def multiply(array, factor):
... print("Calculating...")
... return factor*array
>>> multiply(array, 2)
Calculating...
array([[ 2, 4, 6],
[ 8, 10, 12]])
>>> multiply(array, 2)
array([[ 2, 4, 6],
[ 8, 10, 12]])
>>> multiply.cache_info()
CacheInfo(hits=1, misses=1, maxsize=256, currsize=1)
"""
def decorator(function):
@wraps(function)
def wrapper(np_array, *args, **kwargs):
hashable_array = array_to_tuple(np_array)
return cached_wrapper(hashable_array, *args, **kwargs)
@lru_cache(*args, **kwargs)
def cached_wrapper(hashable_array, *args, **kwargs):
array = np.array(hashable_array)
return function(array, *args, **kwargs)
def array_to_tuple(np_array):
"""Iterates recursivelly."""
try:
return tuple(array_to_tuple(_) for _ in np_array)
except TypeError:
return np_array
# copy lru_cache attributes over too
wrapper.cache_info = cached_wrapper.cache_info
wrapper.cache_clear = cached_wrapper.cache_clear
return wrapper
return decorator
虽然这并不能直接解决您的问题,但是可以很容易地将其推广到任意数量的输入参数。
https://stackoverflow.com/questions/46544940
复制相似问题