使用dict的递归阶乘会导致RecursionError

时间:2016-01-10 14:46:53

标签: python dictionary recursion

一个简单的递归因子方法非常有效:

crawl()

但我想稍微尝试一下并使用def fact(n): if n == 0: return 1 return n * fact(n-1) 代替。从逻辑上讲,这应该可行,但是一堆打印语句告诉我dict而不是停留在n,在负数上下滑,直到达到最大递归深度:

0

为什么?

1 个答案:

答案 0 :(得分:17)

Python不会懒惰地评估参数。

在调用dict.get之前,还会评估传递给dict.get调用的默认值。

因此,在您的情况下,默认值具有递归调用,并且由于您的条件从未得到满足,因此它会进行无限递归。

您可以使用此程序确认此信息

>>> def getter():
...     print("getter called")
...     return 0
... 
>>> {0: 1}.get(0, getter())
getter called
1

即使字典中存在键0,由于将评估传递给Python中函数的所有参数,因此在实际getter之前也会调用dict.get。 / p>

如果你想要做的就是在评估了值时避免多次递归计算,那么你使用functools.lru_cache,如果你使用的是Python 3.2 +

>>> @functools.lru_cache()
... def fact(n):
...     print("fact called with {}".format(n))
...     if n == 0:
...         return 1
...     return n * fact(n-1)
... 
>>> fact(3)
fact called with 3
fact called with 2
fact called with 1
fact called with 0
6
>>> fact(4)
fact called with 4
24

这个装饰器只是缓存传递参数的结果,如果再次进行相同的调用,它只会从缓存中返回值。

如果要修复自定义缓存功能,则需要在函数外部定义look_up,以便在调用函数时不会创建它。

>>> look_up = {0: 1}
>>> def fact(n):
...     if n not in look_up:
...         print("recursing when n is {}".format(n))
...         look_up[n] = n * fact(n - 1)
...     return look_up[n]
... 
>>> fact(3)
recursing when n is 3
recursing when n is 2
recursing when n is 1
6
>>> fact(4)
recursing when n is 4
24
>>> fact(4)
24

否则您可以使用默认参数,例如

>>> def fact(n, look_up={0: 1}):
...     if n not in look_up:
...         print("recursing when n is {}".format(n))
...         look_up[n] = n * fact(n - 1)
...     return look_up[n]