You don't really gain anything by storing the cache as a dictionary since in order to calculate f(n) you need to know f(n-1) (and f(n-2)). In other words, your dictionary will always have keys from 2-n. You might as well just use a list instead (it's only an extra 2 elements). Here's a version which caches properly and doesn't hit the recursion limit (ever):
import time cache = [1,1] def dynamic_fib(n): #print n if n >= len(cache): for i in range(len(cache),n): dynamic_fib(i) cache.append(dynamic_fib(n-1) + dynamic_fib(n-2)) print "caching %d" % n return cache[n] if __name__ == "__main__": start = time.time() a = dynamic_fib(4000) print "Dynamic",a print (time.time() - start)
Note that you could do the same thing with a dict, but I'm almost positive that a list will be faster.
Just for fun, here's a bunch of options (and timings!):
def fib_iter(n): a, b = 1, 1 for i in xrange(n): a, b = b, a + b return a memo_iter = [1,1] def fib_iter_memo(n): if n == 0: return 1 else: try: return memo_iter[n+1] except IndexError: a,b = memo_iter[-2:] for i in xrange(len(memo_iter),n+2): a, b = b, a + b memo_iter.append(a) return memo_iter[-1] dyn_cache = [1,1] def dynamic_fib(n): if n >= len(dyn_cache): for i in xrange(len(dyn_cache),n): dynamic_fib(i) dyn_cache.append(dynamic_fib(n-1) + dynamic_fib(n-2)) return dyn_cache[n] dyn_cache2 = [1,1] def dynamic_fib2(n): if n >= len(dyn_cache2): for i in xrange(len(dyn_cache2),n): dynamic_fib2(i) dyn_cache2.append(dyn_cache2[-1] + dyn_cache2[-2]) return dyn_cache2[n] cache_fibo = [1,1] def dyn_fib_simple(n): while len(cache_fibo) <= n: cache_fibo.append(cache_fibo[-1]+cache_fibo[-2]) return cache_fibo[n] import timeit for func in ('dyn_fib_simple','dynamic_fib2','dynamic_fib','fib_iter_memo','fib_iter'): print timeit.timeit('%s(100)'%func,setup='from __main__ import %s'%func),func print fib_iter(100) print fib_iter_memo(100) print fib_iter_memo(100) print dynamic_fib(100) print dynamic_fib2(100) print dyn_fib_simple(100)
And the results:
0.269892930984 dyn_fib_simple 0.256865024567 dynamic_fib2 0.241492033005 dynamic_fib 0.222282171249 fib_iter_memo 7.23831701279 fib_iter 573147844013817084101 573147844013817084101 573147844013817084101 573147844013817084101 573147844013817084101 573147844013817084101
RuntimeError: maximum recursion depth exceededThis limit prevents infinite recursion from causing an overflow of the C stack and crashing Python.