首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为类和静态方法配置lru_cache

为类和静态方法配置lru_cache
EN

Stack Overflow用户
提问于 2017-10-03 12:44:58
回答 3查看 7.8K关注 0票数 11

我试图在lru_cache中使用Python3来加速对Salesforce数据库的常见查询。下面是相关代码,应该是

  • ( a)将不可理解的论点转换为可理解的论点,及
  • b)为这些对象启用LRU缓存。

当我尝试这段代码时,缓存用于调用没有参数的函数,但它似乎不缓存带有参数的函数调用。另外,我也不知道如何为装饰的功能定购装饰师。

注意,我在这里使用了一个类以及类和静态方法,这样我就可以为不同的get子类重写Resourceget_all方法。

请解释我做错了什么或可能做得更好。

代码语言:javascript
运行
复制
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
EN

回答 3

Stack Overflow用户

发布于 2020-06-27 01:40:03

不需要额外的包裹。预期的下列工作:

代码语言:javascript
运行
复制
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

票数 11
EN

Stack Overflow用户

发布于 2018-10-15 05:32:40

这应该是您正在寻找的答案:https://ring-cache.readthedocs.io/en/latest/quickstart.html#method-classmethod-staticmethod

lru_cache只支持简单的函数。Ring提供了非常相似的接口,但包含任何类型的描述符支持。

代码语言:javascript
运行
复制
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。

票数 3
EN

Stack Overflow用户

发布于 2018-10-12 09:33:44

如果我为你来晚了,那就走吧,因为这是我的回应。你搞错了几件事。

首先,在args函数定义中覆盖wappedkwargs。这有效地删除了您的函数参数。

其次,您只在kwargs中生成不可变的列表,而不是在args中。

而且,lru_cache是一个装饰构造函数,所以它必须被称为@lru_cache()。我不知道没有它对你有什么用。

此外,您将def get(cls, ...函数声明为@staticmethod,那么它将不会收到cls参数。

但是--最重要的是,--在类中定义一个装饰器并不像这篇媒体文章中所说的那样简单。我明白了您想要做的事情:通过继承强制缓存,虽然这看起来是个好主意,但它不能正常工作。如果您重写一个函数,您将不得不再次用缓存重新装饰它,这就忽略了在类中声明装饰器的意义。

为了结束它,我会省去自己的问题,在一个不同的类中声明装饰器,并在其他地方使用它。但是要小心,因为缓存类方法也不是简单的。

额外:

几周前,我也遇到过类似的情况,我想要缓存一个接受numpy数组的函数。我想出了基于这一实现这是如此的反应。我只需将数组转换为元组,并再次重构它(因为我需要它在末尾是一个可变数组)。

代码语言:javascript
运行
复制
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

虽然这并不能直接解决您的问题,但是可以很容易地将其推广到任意数量的输入参数。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46544940

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档