使用带有字典参数的@functools.lru_cache

新手上路,请多包涵

我有一个方法将(除其他外)字典作为参数。该方法正在解析字符串,字典提供了一些子字符串的替换,因此它不必是可变的。

这个函数经常被调用,并且在冗余元素上,所以我认为缓存它会提高它的效率。

但是,正如您可能已经猜到的那样,由于 dict 是可变的,因此不可散列, @functools.lru_cache 无法修饰我的函数。那么我该如何克服呢?

如果它只需要标准库类和方法,则加分。理想情况下,如果它在标准库中存在某种我从未见过的 frozendict 会让我开心。

PS: namedtuple 只能在不得已的情况下使用,因为它需要大的语法转换。

原文由 Evpok 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 718
2 个回答

不要使用自定义的可散列字典,而是使用它并避免重新发明轮子!这是一本可哈希的冻结字典。

https://pypi.org/project/frozendict/

代码:

 from frozendict import frozendict

def freezeargs(func):
    """Transform mutable dictionnary
    Into immutable
    Useful to be compatible with cache
    """

    @functools.wraps(func)
    def wrapped(*args, **kwargs):
        args = tuple([frozendict(arg) if isinstance(arg, dict) else arg for arg in args])
        kwargs = {k: frozendict(v) if isinstance(v, dict) else v for k, v in kwargs.items()}
        return func(*args, **kwargs)
    return wrapped

接着

@freezeargs
@lru_cache
def func(...):
    pass

代码取自@fast_cen 的回答

注意:这不适用于递归数据结构;例如,您可能有一个列表参数,它是不可散列的。您被邀请使包装递归,这样它就深入到数据结构中,并使每个 dict 冻结和每个 list 元组。

(我知道 OP 不再需要解决方案,但我来这里寻找相同的解决方案,所以留给后代)

原文由 Cedar 发布,翻译遵循 CC BY-SA 4.0 许可协议

这是一个使用@mhyfritz 技巧的装饰器。

 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()))

    @functools.wraps(func)
    def wrapped(*args, **kwargs):
        args = tuple([HDict(arg) if isinstance(arg, dict) else arg for arg in args])
        kwargs = {k: HDict(v) if isinstance(v, dict) else v for k, v in kwargs.items()}
        return func(*args, **kwargs)
    return wrapped

只需将它添加到您的 lru_cache 之前。

 @hash_dict
@functools.lru_cache()
def your_function():
    ...

原文由 fast_cen 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题