0

How to use lru_cache for static method and with unhashable arguments like lists in python

I have tried using methodtools lru_cache method. It gives an error that call is not working.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 3
    Please give a minimum reproducible code example with the full error message – Caridorc Jan 16 '23 at 14:00
  • "with unhashable arguements like lists" - if you want to cache outputs, your function shouldn't be designed to *take* mutable arguments in the first place. – user2357112 Jan 16 '23 at 14:02

1 Answers1

0

You could use a separate decorator to sanitize the inputs. Something like this:

def sanitize_args(*expected_types):
    def make_decorator(decorated):
        @functools.wraps(decorated)
        def decorator(*args):
            if len(args) != len(expected_types):
                raise TypeError("Wrong number of arguments")
            args = (type_(arg) for type_, arg in zip(expected_types, args))
            return decorated(*args)
        return decorator
    return make_decorator


class Foo:
    @staticmethod
    @sanitize_args(tuple, str)
    @functools.lru_cache
    def bar(sequence, label):
        return (label, sum(sequence))


print(Foo.bar([1, 2, 3], "foo"))

However, getting this right (and fast) in a generic fashion is a bit tedious. Note how I left out keyword arguments for simplicity.

An easier solution is to use an uncached public interface with an lru-cached private implementation. Something like this:

class Foo:
    @staticmethod
    @functools.lru_cache
    def _implement_bar(sequence, label):
        return (label, sum(sequence))

    @staticmethod
    def bar(sequence, label):
        return Foo._implement_bar(tuple(sequence), str(label))
Homer512
  • 9,144
  • 2
  • 8
  • 25