Skip to content
Advertisement

Using @functools.lru_cache with dictionary arguments

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 doesn’t have to be mutable.

This function is called quite often, and on redundant elements so I figured that caching it would improve its efficiency.

But, as you may have guessed, since dict is mutable and thus not hashable, @functools.lru_cache can’t decorate my function. So how can I overcome this?

Bonus point if it needs only standard library classes and methods. Ideally if it exists some kind of frozendict in standard library that I haven’t seen it would make my day.

PS: namedtuple only in last resort, since it would need a big syntax shift.

Advertisement

Answer

Instead of using a custom hashable dictionary, use this and avoid reinventing the wheel! It’s a frozen dictionary that’s all hashable.

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

Code:

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

and then

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

Code taken from @fast_cen ‘s answer

Note: this does not work on recursive datastructures; for example, you might have an argument that’s a list, which is unhashable. You are invited to make the wrapping recursive, such that it goes deep into the data structure and makes every dict frozen and every list tuple.

(I know that OP nolonger wants a solution, but I came here looking for the same solution, so leaving this for future generations)

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement