为啥在这里使用 `any` 会导致该程序超出递归深度,但使用 `for` 循环不会?
Posted
技术标签:
【中文标题】为啥在这里使用 `any` 会导致该程序超出递归深度,但使用 `for` 循环不会?【英文标题】:Why does using `any` here cause this program to exceed recursion depth, but using a `for` loop doesn't?为什么在这里使用 `any` 会导致该程序超出递归深度,但使用 `for` 循环不会? 【发布时间】:2021-12-16 14:24:40 【问题描述】:输入
sum_possible(2017, [4, 2, 10]) # -> False
使用any
导致RecursionError: maximum recursion depth exceeded
def sum_possible(amount, numbers, cache = None):
if cache is None:
cache =
if amount in cache:
return cache[amount]
if amount == 0:
return True
if amount < 0:
return False
cache[amount] = any(sum_possible(amount - number, numbers, cache) for number in numbers)
return cache[amount]
使用解决方案的for
循环
def sum_possible(amount, numbers, cache = None):
if cache is None:
cache =
if amount in cache:
return cache[amount]
if amount == 0:
return True
if amount < 0:
return False
for number in numbers:
if sum_possible(amount - number, numbers, cache):
cache[amount] = True
return True
cache[amount] = False
return False
【问题讨论】:
【参考方案1】:默认递归限制为 1000 次调用。虽然它被称为“递归限制”,但它实际上是所有嵌套函数调用的最大深度——我们只是用递归来描述它,因为没有递归就很难达到极限——你需要数百个不同的函数相互调用.超出递归限制的最常见原因是“无限”递归(例如,未能正确检测基本情况)。
在带有for
循环的版本中,允许1000 个递归级别。连同缓存一起,这对于您的测试用例来说已经足够了。
在使用any()
的版本中,有效递归限制减半,因为每个递归调用都在对any()
的调用中。这还不够。
【讨论】:
我认为通过明确说明所谓的“递归限制”实际上与“递归”没有直接关系,而是更普遍地与 所有功能有关,我认为答案可能会更容易理解调用,而不仅仅是递归函数调用。从理论上讲,只要写很长的any(any(any(any(any(any(any(any(any(any(any(any(any(...
就可以在没有任何递归的情况下超过它
@Stef 我已经更新了答案。我不认为这样的嵌套调用会成为问题,因为每个调用都发生在前一个调用完成之后,而不是在它正在进行时。此外,any()
不返回序列,因此它不能作为 any()
的参数。
“我认为这样的嵌套调用不会有问题,因为每个调用都发生在前一个调用完成之后,而不是在它正在进行时。” 呃。你当然是对的。如果它是一个更简单的函数f
,称为f(f(f(...)))
,那么这不会增加深度,因为函数的参数是在调用函数之前评估的。 OP 遇到此问题的原因是递归调用在生成器表达式内,而不是直接在 any
内。 “评估生成器表达式”除了返回生成器之外没有太大影响。但随后
但是当any
已经开始评估时,对sum_possible(amount - number, numbers, cache)
的调用被评估,此时any
调用生成器的.__next__
。所以这个问题是因为生成器而发生的,而不是因为any
。如果 OP 使用列表理解而不是生成器表达式,则不会发生这种情况:any([sum_possible(amount - number, numbers, cache) for number in numbers])
。虽然那时会有另一个问题:***.com/questions/69773670/…
没错。这就是为什么我们在any()
版本中得到两个级别的调用——any()
自己进行递归调用。以上是关于为啥在这里使用 `any` 会导致该程序超出递归深度,但使用 `for` 循环不会?的主要内容,如果未能解决你的问题,请参考以下文章
为啥导致 ***Error 的递归方法的调用次数在程序运行之间会有所不同? [复制]