How to hash *args **kwargs for function cache?

python

Solution

Here is the technique used in `functools.lru_cache()`:

kwd_mark = object()     # sentinel for separating args from kwargs

def cached_call(*args, **kwargs):
    key = args + (kwd_mark,) + tuple(sorted(kwargs.items()))
    return cache.get(key)

Note, the above code handles keyword arguments but makes no attempt to handle non-hashable values like lists. Your idea for using the `str` or a `list` is a reasonable start. For `set` objects, you would need to sort the entries first, `str(sorted(someset))`. Other objects may not have a useful `__repr__` or `__str__` (i.e. they may show only the object type and location in memory). In summary, handling arbitrary unhashable arguments requires careful consideration of each object type.

Problem

I'm working with `xlwt` which has a 4k limit on how many styles can be defined in an excel doc. Normally, one creates styles like so: ``` style = xlwt.easyxf("font: bold 1") ``` Which I simply replaced with ``` def cached_easyxf(self, format): return self._cache.setdefault(format, xlwt.easyxf(format)) ``` Which works perfectly. Now, I've found out that I need to pass in keyword arguments sometimes which got me thinking: how should I hash the args/kwargs signature? Should I create a cache key based on str(value)? Pickle? What's most robust? For my situation it looks like I can just convert key/values to strings and add it to my keys... but I'm now curious about a generic way to handle this with say unhashable types like `arg=[1, 2, 3]` ``` def cached_call(*args, **kwargs): return cache.get(what_here) cached_call('hello') cached_call([1, 2, 3], {'1': True}) ```

Original source

Related problems