问题描述
假设您想获得第 n 个斐波那契数。那么,一种可能是使用递归函数
def Fib(n,d):
"""Assumes n is an int >= 0,d dictionary
Returns nth Fibonacci number"""
if n in d:
return d[n]
else:
d[n] = Fib(n-1,d) + Fib(n-2,d)
return d[n]
这很好用。我试图将其缩短为
def Fib(n,d):
return d.setdefault(n,Fib(n-1,d))
但是当我可以调用它时
d={0:1,1:1}
print(f(2,d))
,甚至使用 f(1,d),它都会进入无限循环,并重新启动内核。事实上,这种形式的任何函数,比如说
def f(n,d):
return d.setdefault(n,f(n-1,d))
有同样的问题。当我试图调试这个时,我看到 n 不断减少传递值 1。我想我不明白这个方法的实现。我假设setdefault方法首先检查key是否在字典中并返回值,如果没有,则将默认值分配给key并返回默认值。我在这里缺少什么?(我使用 Python 3.9.1 和 Spyder 4.2.0)
解决方法
你仍然需要一个基本情况,否则没有什么可以阻止它计算,fib(-1)
,fib(-2)
,fib(-99)
,...
def fib(n,d):
return n if n < 2 else d.setdefault(n,fib(n-1,d) + fib(n-2,d))
print(fib(10,{0:0,1:1}))
55
您在使用 setdefault
时遇到的问题是 python 是一种应用顺序语言。这意味着函数参数在调用函数之前被评估。在 setdefault
的情况下,我们将在尝试在 fib(n-1,d)
中查找 n
之前评估 d
。
更好的接口可能是 dict.setdefault(key,lambda: somevalue)
,如果需要设置默认值,则 仅 执行 lambda。我们可以把它写成下面的 lazydefault
-
def lazydefault(d,key,lazyvalue):
if key not in d:
d[key] = lazyvalue()
return d[key]
def fib(n,d):
return lazydefault(d,n,lambda: fib(n-1,1:1}))
55