简体   繁体   English

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

[英]Python dictionary setdefault() method used as a return value of a recursive function

Say you want to get the nth Fibonacci Number.假设您想获得第 n 个斐波那契数。 Then, one possibility is to use the recursive function然后,一种可能性是使用递归 function

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]

This works quite well.这工作得很好。 I tried to shorten this to我试图将其缩短为

 def Fib(n, d):
        return d.setdefault(n, Fib(n-1, d) + Fib(n-2, d))

But when I can call it with但是当我可以用

d={0:1, 1:1}
print(f(2, d))

, or even with f(1,d), it goes into infinite loop, and restarts the kernel. ,或者甚至使用 f(1,d),它进入无限循环,并重新启动 kernel。 In fact, any function of this form, say事实上,任何这种形式的 function,比如说

def f(n, d):
    return d.setdefault(n, f(n-1,d))

has the same problem.有同样的问题。 When I tried to debug this, I saw that n keeps decreasing pass the value 1. I guess I don't understand the implementation of this method.当我尝试调试这个时,我看到 n 不断减小,通过值 1。我想我不明白这个方法的实现。 I presumed that the setdefault method first checks whether the key is in the dictionary and returns the value, and if not, then assigns the default value to the key and returns the default value.我假设 setdefault 方法首先检查 key 是否在字典中并返回值,如果没有,则将默认值分配给 key 并返回默认值。 What am I missing here?(I am using Python 3.9.1 with Spyder 4.2.0)我在这里缺少什么?(我正在使用 Python 3.9.1 和 Spyder 4.2.0)

You still need a base case otherwise there's nothing to stop it from calculating, fib(-1) , fib(-2) , fib(-99) , ...你仍然需要一个基本情况,否则没有什么可以阻止它计算, 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

The problem you are experiencing with setdefault is that python is an applicative order language.您在使用setdefault时遇到的问题是 python 是一种应用命令语言。 That means a functions arguments are evaluated before a the function is called.这意味着在调用 function之前评估函数 arguments 。 In the case of setdefault , we will evaluate fib(n-1,d) + fib(n-2,d) before we attempt to lookup n in d .setdefault的情况下,我们将在尝试在d中查找n之前评估fib(n-1,d) + fib(n-2,d)

A better interface might be dict.setdefault(key, lambda: somevalue) where the lambda is executed only if the default needs to be set.更好的接口可能是dict.setdefault(key, lambda: somevalue) ,其中 lambda在需要设置默认值时才执行。 We could write this as lazydefault below -我们可以把它写成下面的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, d) + fib(n-2, d))

print(fib(10, {0:0, 1:1}))
55

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM