Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

caching last k results of a function in python

I want to write a function that accepts a single-argument function f, and an integer k, and returns a function that behaves the same as f except it caches the last k results of f.

For instance, if memoize is the function we're after, and let mem_f = memoize(f, 2), then:

    mem_f(arg1) -> f(arg1) is computed and cached  
    mem_f(arg1) -> f(arg1) is returned from cache  
    mem_f(arg2) -> f(arg2) is computed and cached  
    mem_f(arg3) -> f(arg3) is computed and cached, and f(arg1) is evicted

What I have done is:

def memoize(f,k):
    cache = dict()

    def mem_f(*args):
        if args in cache:
            return cache[args]
        result = f(*args)
        cache[args]= result
        return result 
    return mem_f

This function returns the result from cache and if it is not in cache, it is computed and cached. However, I am not clear how to cache only last k results of f? I am newbie, any help would be appreciated.

like image 286
FJ_Abbasi Avatar asked Jan 31 '26 23:01

FJ_Abbasi


2 Answers

You could just use functools.lru_cache to do the caching. I accepts a maxsize parameter to control how much it caches:

from functools import lru_cache

@lru_cache(maxsize=2)
def test(n):
    print("calling function")
    return n * 2

print(test(2))
print(test(2))
print(test(3))
print(test(3))
print(test(4))
print(test(4))
print(test(2))

results:

calling function
4
4
calling function
6
6
calling function
8
8
calling function
4

like image 52
Mark Avatar answered Feb 03 '26 12:02

Mark


Expanding on the excellent suggestion of Mark Meyer, here's what the solution looks like using lru_cache and the terminology of your question:

from functools import lru_cache


def memoize(f, k):
    mem_f = lru_cache(maxsize=k)(f)
    return mem_f


def multiply(a, b):
    print("Called with {}, {}".format(a, b))
    return a * b


def main():
    memo_multiply = memoize(multiply, 2)
    print("Answer: {}".format(memo_multiply(3, 4)))
    print("Answer: {}".format(memo_multiply(3, 4)))
    print("Answer: {}".format(memo_multiply(3, 7)))
    print("Answer: {}".format(memo_multiply(3, 8)))


if __name__ == "__main__":
    main()

Result:

Called with 3, 4
Answer: 12
Answer: 12
Called with 3, 7
Answer: 21
Called with 3, 8
Answer: 24
like image 38
augray Avatar answered Feb 03 '26 13:02

augray