使用下面常见的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:value
对5:fib(5)
(因为尚未看到5)。但是v
对中的k:v
是对fib(5)的函数调用,它仍然需要返回它的值,我认为这需要经历整个递归过程。如果我们试图缓存返回值,memoization如何获得fib(5)的返回值而不经历整个递归过程?
答案 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)