跟踪缓存的Fibonacci序列的执行(使用python decorator)

时间:2015-03-19 20:55:16

标签: python caching recursion decorator memoization

使用下面常见的memoization模式和fibonnaci函数,我在查看它的实际工作方式时遇到了一些麻烦。我理解这个概念,但是通过这个程序思考我会感到困惑并开始思考。

def memoize(func):
    cache={}
    def wrapper(*args,**kwargs):
        if args in cache:
            return cache[args]
        else:
            cache[args]=func(*args) #to store the result, doesn't fib still have to go through all it's calculations here?
            return cache[args]
    return wrapper

@memoize
def fib(n):
    if n==0:
        return 0
    elif n==1:
        return 1
    else:
        return fib(n-2)+fib(n-1)

所以从概念上讲,我理解递归是如何工作的,我理解了memoization背后的想法(首先尝试查看它以避免多次运行相同的calc)。令我困惑的是,当你为一个函数调用添加一个键而没有看到参数时,如何在不经过完整函数调用的情况下完成。

例如,如果我们调用fib(5),那么当我们点击cache[args]=func(*args)时,我们会在字典中添加key:value5:fib(5)(因为尚未看到5)。但是v对中的k:v是对fib(5)的函数调用,它仍然需要返回它的值,我认为这需要经历整个递归过程。如果我们试图缓存返回值,memoization如何获得fib(5)的返回值而不经历整个递归过程?

1 个答案:

答案 0 :(得分:0)

你说:“但是k:v对中的v是对fib(5)的函数调用,它仍然需要返回它的值,我认为这需要经历整个递归过程。”我认为这里的v是函数返回的值,所以当你再次遇到相同的k时,它会在缓存中找到并返回。

我在您的代码中添加了一些打印输出,以查看发生了什么。级别将是递归级别:

def memoize(func):
    cache={}
    def wrapper(*args,**kwargs):
        if args[0] in cache:
            print("  "*args[1]+"in cache: fib("+str(args[0])+")")
            return cache[args[0]]
        else:
            cache[args[0]]=func(*args)
            return cache[args[0]]
    return wrapper

@memoize
def fib(n, level):
    print("  "*level+"fib("+str(n)+")")
    if n==0:
        return 0
    elif n==1:
        return 1
    else:
        return fib(n-2, level+1)+fib(n-1, level+1)

因此fib(5,0)的结果如下:

fib(5)
  fib(3)
    fib(1)
    fib(2)
      fib(0)
      in cache: fib(1)
  fib(4)
    in cache: fib(2)
    in cache: fib(3)