Python 字典 setdefault() 方法用作递归函数的返回值

问题描述

假设您想获得第 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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...