【问题标题】: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

【问题讨论】:

    标签: python recursion caching dynamic-programming


    【解决方案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])。虽然那时会有另一个问题:stackoverflow.com/questions/69773670/…
    • 没错。这就是为什么我们在any() 版本中得到两个级别的调用——any() 自己进行递归调用。
    猜你喜欢
    • 2021-12-14
    • 1970-01-01
    • 2019-05-29
    • 2013-12-13
    • 2014-06-15
    • 2013-04-30
    • 2016-08-24
    • 2021-01-26
    • 1970-01-01
    相关资源
    最近更新 更多