设置函数的python递归限制

时间:2011-08-04 17:08:50

标签: python recursion

我有一个解决递归问题的方法,我需要一个函数(实际上是一个方法)。我希望它是递归的,但是我想将递归限制设置为10并在调用函数后重置它(或者根本没有使用递归限制)。任何人都可以想到一个更好的方法来做这个或建议使用其中一个吗?我倾向于上下文管理器,因为它使我的代码更清晰,没有设置tracebacklimit,但可能有警告?

import sys

def func(i=1):
    print i
    if i > 10:
        import sys
        sys.tracebacklimit = 1
        raise ValueError("Recursion Limit")
    i += 1
    func(i)

class recursion_limit(object):
    def __init__(self, val):
        self.val = val
        self.old_val = sys.getrecursionlimit()
    def __enter__(self):
        sys.setrecursionlimit(self.val)
    def __exit__(self, *args):
        sys.setrecursionlimit(self.old_val)
        raise ValueError("Recursion Limit")

def func2(i=1):
    """
    Call as

    with recursion_limit(12):
        func2()
    """
    print i
    i += 1
    func2(i)

if __name__ == "__main__":
    #    print 'Running func1'
    #    func()

    with recursion_limit(12):
        func2()

我确实通过上下文管理器看到了一些奇怪的行为。如果我放入主

with recursion_limit(12):
    func2()

它打印1到10.如果我从解释器中执行相同操作,它会打印1到11.我假设在导入内容时会发生什么事情?

编辑:对于后人来说,这是我为一个知道其调用深度的函数提出的。我怀疑我会在任何生产代码中使用它,但它完成了工作。

import sys
import inspect
class KeepTrack(object):
    def __init__(self):
        self.calldepth = sys.maxint

    def func(self):
        zero = len(inspect.stack())
        if zero < self.calldepth:
            self.calldepth = zero
        i = len(inspect.stack())
        print i - self.calldepth
        if i - self.calldepth < 9:
            self.func()

keeping_track = KeepTrack()
keeping_track.func()

4 个答案:

答案 0 :(得分:7)

您根本不应该更改系统递归限制。你应该编写你的函数来知道它的深度,并在它变得太深时结束递归。

递归限制似乎在您的程序和解释器中应用不同的原因是因为它们具有不同的堆栈顶部:在解释器中调用的函数以达到运行代码的程度。

答案 1 :(得分:1)

虽然有点切向(我已将它放在评论中,但我认为没有空间),但应该注意的是setrecursionlimit有点误导性命名 - 它实际上设置了最大堆栈深度:

http://docs.python.org/library/sys.html#sys.setrecursionlimit

这就是为什么函数的行为会有所不同,具体取决于您调用它的位置。另外,如果func2要进行stdlib调用(或者其他什么),最终调用了多个函数,使得它向堆栈添加了超过N的值,那么异常会提前触发。

另外,我也不会改变sys.tracebacklimit;这将对你的程序的其余部分产生影响。和Ned一起回答。

答案 2 :(得分:1)

忽略更一般的问题,看起来你可以通过查看inspect.getouterframes()的长度来获得当前帧深度。这会给你一个“零点”,你可以从中设置深度限制(免责声明:我没试过这个)。

编辑:或len(inspect.stack()) - 我不清楚它的区别是什么。我很想知道这是否有效,以及它们是否不同。

答案 3 :(得分:0)

我绝对会选择第一种方法,它更简单,更自我解释。在所有递归限制都是你明确的选择之后,为什么要混淆呢?