2016-11-06 67 views
3

我有以下形式的函数:如何消除在Python函数的递归包含控制流

def my_func(my_list): 
    for i, thing in enumerate(my_list): 
     my_val = another_func(thing) 

     if i == 0: 
      # do some stuff 
     else: 
      if my_val == something: 
       return my_func(my_list[:-1]) 
      # do some other stuff 

递归部分获取调用,以至于我得到一个RecursionError,所以我想用来替换一个while循环,如here所解释的,但我无法弄清楚如何与函数中的控制流语句进行协调。任何帮助将感激地收到!

+0

,如果我们知道这些功能实际上做 –

+0

你必须提供所有的'return'点,以递归转换为迭代这将是有益的。 – outoftime

+0

再次检查我的答案。 – outoftime

回答

1
def my_func(my_list): 
    run = True 
    while run: 
     for i, thing in enumerate(my_list): 
      my_val = another_func(thing) 

      if i == 0: 
       # do some stuff 
      else: 
       if my_val == something: 
        my_list = my_list[:-1] 
        break 
       # do some other stuff  

这是一种迭代方法。

装饰

class TailCall(object): 
    def __init__(self, __function__): 
     self.__function__ = __function__ 
     self.args = None 
     self.kwargs = None 
     self.has_params = False 

    def __call__(self, *args, **kwargs): 
     self.args = args 
     self.kwargs = kwargs 
     self.has_params = True 
     return self 

    def __handle__(self): 
     if not self.has_params: 
      raise TypeError 
     if type(self.__function__) is TailCaller: 
      return self.__function__.call(*self.args, **self.kwargs) 
     return self.__function__(*self.args, **self.kwargs) 


class TailCaller(object): 
    def __init__(self, call): 
     self.call = call 

    def __call__(self, *args, **kwargs): 
     ret = self.call(*args, **kwargs) 
     while type(ret) is TailCall: 
      ret = ret.__handle__() 
     return ret 

@TailCaller 
def factorial(n, prev=1): 
    if n < 2: 
     return prev 
    return TailCall(factorial)(n-1, n * prev) 

要使用这个装饰简单地用@TailCaller装饰包裹你的函数,并返回TailCall实例与所需的PARAMS初始化。

我想说谢谢你的灵感@ o2genum凯尔·米勒谁写an excellent article about this problem

尽管删除此限制有多么好,但您可能需要知道why this feature is not officially supported的 。

2

可能有一个很好的确切答案,但是从递归切换到迭代的最普通(或者可能是快速和肮脏)的方式是manage the stack yourself。只要手动执行什么编程语言隐含,并拥有自己的无限堆栈。

在这种特定情况下有tail recursion。你看,my_func递归调用的结果没有被调用者以任何方式使用,它立即返回。最后会发生什么呢?最深的递归调用的结果会起泡并正在被返回。这就是@ outoftime解决方案的可能性所在。我们只对进入递归感兴趣,因为从递归返回是微不足道的。所以进入递归通路被替换为迭代。