如何使用python避免嵌套函数中的深度递归

时间:2014-05-27 09:21:32

标签: python function recursion nested depth

说我们有这个代码:

a = 1

def func1():
    if a == 1:
        func2()

def func2():
    if a == 1:
        func3()

def func3():
    func1()

我们是否有办法让func3调用func1 踩出的父函数'它已经招致?意思是,回到递归深度0',好像它刚刚开始新鲜?

谢谢!

3 个答案:

答案 0 :(得分:4)

有些语言提供tail-call optimization,这相当于在创建新的堆栈帧之前丢弃了前一个堆栈帧。它只有在递归调用是最后一次操作时才有可能(否则你需要堆栈帧,因为它指向其余的操作)。但是,Python没有。

您有两种选择:

  1. 如果函数是递归的,但递归不是通过尾调用完成的,那么通常通过向函数签名添加参数来使convert to tail recursion变得简单。 (但是,您的示例中的代码已经采用此形式。)一旦所有递归都通过尾调用完成,convert it to an iterative style通常很简单。
  2. 如果您想避免上述操作,您还可以将代码转换为explicitly uses a stack来存储内容的迭代样式,因为堆栈的大小或多或少是无限制的,而调用堆栈通常很小(导致递归深度限制的原因)。
  3. 请注意,当你有三个以递归方式相互调用的函数时,这两件事情都比较棘手。但总的想法是提出新的代码来保留旧代码的行为而不使用递归,显然你如何做到这将取决于起始代码,尽管一般模式(上面链接)保持不变

    在您的情况下,代码要么进入无限循环,要么根据a进行无效循环,所以

     a = 1
    
     def func3():
         while a == 1:
           pass
    
     func3()
    

    就足够了。

    作为旁注:对于某些算法,memoization可以减少调用次数。如果函数的大输入结果总是由较小输入的结果组成,这些结果被重复计算("overlapping subproblems"),那么您可以保留返回值的全局缓存并在进行新调用之前检查缓存。可以使用decorators在Python中编写通用的memoization代码。

答案 1 :(得分:0)

不知道你想在哪里停止递归,但这可能是一个很好的开始点:

def func1(parents = []):
    print "func1"
    if func1 not in parents:
        parents.append(func1)
        func2(parents)

def func2(parents = []):
    print "func2"
    if func2 not in parents:
        parents.append(func2)
        func3(parents)

def func3(parents = []):
    print "func3"
    if func3 not in parents:
        parents.append(func3)
        func1(parents)

func1()

<强>输出:

func1
func2
func3
func1

答案 2 :(得分:0)

如果你想重复运行func1func2func3的循环,但没有无限递归,你可能想要使用循环而不是递归。

尝试:

def func1():
    pass # do stuff

def func2():
    pass # do more stuff

def func3():
    pass # something completely different

a = 1

while a == 1: # this will loop indefinately, unless one of the functions chages "a"
    func1()
    func2()
    func3()