如何消除包含控制流的Python函数中的递归

时间:2016-11-06 17:18:28

标签: python if-statement for-loop recursion while-loop

我有以下形式的功能:

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,所以我试图用here解释的while循环替换它,但是我无法解决如何调和它函数中的控制流语句。感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

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

在这种特殊情况下,有tail recursion。你看,调用者没有以任何方式使用my_func递归调用结果,它会立即返回。到底发生了什么,最深的递归调用结果会冒泡并且按原样返回。这使得@outoftime的解决方案成为可能。我们只对in-recursion传递感兴趣,因为从递归返回传递是微不足道的。因此,使用迭代替换了入口递归。

答案 1 :(得分: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实例。

我想感谢您对 @ o2genum 以及撰写an excellent article about this problem Kyle Miller 的灵感。

尽管取消这个限制有多好,但你可能必须这样做 了解why this feature is not officially supported