Using @functools.lru_cache with dictionary arguments

前端 未结 6 2034
栀梦
栀梦 2020-12-24 12:16

I have a method that takes (among others) a dictionary as an argument. The method is parsing strings and the dictionary provides replacements for some substrings, so it does

6条回答
  •  孤城傲影
    2020-12-24 13:10

    After deciding to drop lru cache for our use case for now, we still came up with a solution. This decorator uses json to serialise and deserialise the args/kwargs sent to the cache. Works with any number of args. Use it as a decorator on a function instead of @lru_cache. max size is set to 1024.

    def hashable_lru(func):
        cache = lru_cache(maxsize=1024)
    
        def deserialise(value):
            try:
                return json.loads(value)
            except Exception:
                return value
    
        def func_with_serialized_params(*args, **kwargs):
            _args = tuple([deserialise(arg) for arg in args])
            _kwargs = {k: deserialise(v) for k, v in kwargs.items()}
            return func(*_args, **_kwargs)
    
        cached_function = cache(func_with_serialized_params)
    
        @wraps(func)
        def lru_decorator(*args, **kwargs):
            _args = tuple([json.dumps(arg, sort_keys=True) if type(arg) in (list, dict) else arg for arg in args])
            _kwargs = {k: json.dumps(v, sort_keys=True) if type(v) in (list, dict) else v for k, v in kwargs.items()}
            return cached_function(*_args, **_kwargs)
        lru_decorator.cache_info = cached_function.cache_info
        lru_decorator.cache_clear = cached_function.cache_clear
        return lru_decorator
    

提交回复
热议问题