I have a simple little decorator, that caches results from function calls in a dict
as a function attribute.
from decorator import decorator
def _dynamic_programming(f, *args, **kwargs):
try:
f.cache[args]
except KeyError:
f.cache[args] = f(*args, **kwargs)
return f.cache[args]
def dynamic_programming(f):
f.cache = {}
return decorator(_dynamic_programming, f)
I now want to add the possibility to empty the cache. So I change the dynamic_programming()
function like this:
def dynamic_programming(f):
f.cache = {}
def clear():
f.cache = {}
f.clear = clear
return decorator(_dynamic_programming, f)
Now let's assume I use this little thing to implement a Fibonacci number function:
@dynamic_programming
def fib(n):
if n <= 1:
return 1
else:
return fib(n-1) + fib(n-2)
>>> fib(4)
5
>>> fib.cache
{(0,): 1, (1,): 1, (2,): 2, (3,): 3, (4,): 5}
But now when I clear the cache something weird happens:
>>> fib.clear()
>>> fib.cache
{(0,): 1, (1,): 1, (2,): 2, (3,): 3, (4,): 5}
Or (with a new Python kernel running) do it the other way round:
>>> fib.clear()
>>> fib(4)
5
>>> fib.cache
{}
Why is the cache somehow not 'reachable' after the first access to it, i.e. not changing when calling clear()
after a call or a call after a clear()
?
(Btw. I know a solution to clear the cache correctly: calling f.cache.clear()
instead of assigning {}
to it works as expected. I'm merely interested in the reason why the assigning solution fails.)