尝试将打印语句放入代码中以跟踪状态known
:
def fibonacci(n):
print(n, known)
if n in known:
return known[n]
res = fibonacci(n-1) + fibonacci(n-2)
known[n] = res
return res
fibonacci(5)
print(known)
产量
5 {0: 0, 1: 1}
4 {0: 0, 1: 1}
3 {0: 0, 1: 1}
2 {0: 0, 1: 1}
1 {0: 0, 1: 1}
0 {0: 0, 1: 1}
1 {0: 0, 1: 1, 2: 1}
2 {0: 0, 1: 1, 2: 1, 3: 2}
3 {0: 0, 1: 1, 2: 1, 3: 2, 4: 3}
{0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5}
第一个(整数)值是 的值n
。如您所见,fibonacci(5)
被称为 then fibonacci(4)
、 then fibonacci(3)
、 thenfibonacci(2)
等等。这些调用都是由于Python遇到
res = fibonacci(n-1) + fibonacci(n-2)
并递归调用fibonacci(n-1)
. 请记住,Python 从左到右计算表达式。所以只有在
调用fibonacci(n-1)
返回之后。fibonacci(n-2)
为了更好地理解递归函数调用的顺序,你可以使用这个装饰器:
import functools
def trace(f):
"""This decorator shows how the function was called.
Especially useful with recursive functions."""
indent = ' ' * 2
@functools.wraps(f)
def wrapper(*arg, **kw):
arg_str = ', '.join(
['{0!r}'.format(a) for a in arg]
+ ['{0} = {1!r}'.format(key, val) for key, val in kw.items()])
function_call = '{n}({a})'.format(n=f.__name__, a=arg_str)
print("{i}--> {c}".format(
i=indent * (trace.level), c=function_call))
trace.level += 1
try:
result = f(*arg, **kw)
print("{i}<-- {c} returns {r}".format(
i=indent * (trace.level - 1), c=function_call, r=result))
finally:
trace.level -= 1
return result
trace.level = 0
return wrapper
known = {0:0, 1:1}
@trace
def fibonacci(n):
# print(n, known)
if n in known:
return known[n]
res = fibonacci(n-1) + fibonacci(n-2)
known[n] = res
return res
fibonacci(5)
print(known)
产生
--> fibonacci(5)
--> fibonacci(4) # fibonacci(5) calls fibonacci(4)
--> fibonacci(3) # fibonacci(4) calls fibonacci(3)
--> fibonacci(2) # fibonacci(3) calls fibonacci(2)
--> fibonacci(1) # fibonacci(2) calls fibonacci(1)
<-- fibonacci(1) returns 1
--> fibonacci(0) # fibonacci(2) calls fibonacci(0)
<-- fibonacci(0) returns 0
<-- fibonacci(2) returns 1
--> fibonacci(1) # fibonacci(3) calls fibonacci(1)
<-- fibonacci(1) returns 1
<-- fibonacci(3) returns 2
--> fibonacci(2) # fibonacci(4) calls fibonacci(2)
<-- fibonacci(2) returns 1
<-- fibonacci(4) returns 3
--> fibonacci(3) # fibonacci(5) calls fibonacci(3)
<-- fibonacci(3) returns 2
<-- fibonacci(5) returns 5
{0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5}
您可以通过每个递归调用来自的缩进级别来判断。