Установить предел рекурсии python для функции

У меня есть 2 решения проблемы рекурсии, которые мне нужны для функции (фактически метода). Я хочу, чтобы он был рекурсивным, но я хочу установить предел рекурсии на 10 и reset после того, как функция вызывается (или вообще не путается с рекурсивным ограничением). Может ли кто-нибудь подумать о лучшем способе сделать это или рекомендовать использовать один над другими? Я склоняюсь к менеджеру контекста, потому что он очищает мой код и не устанавливает значение 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. Я предполагаю, что что-то происходит под капотом, когда я импортирую вещи?

EDIT: для потомков это то, что я придумал для функции, которая знает глубину его вызова. Я сомневаюсь, что я буду использовать его в любом производственном коде, но он выполнит эту работу.

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()

Ответ 1

Вы не должны изменять лимит рекурсии системы вообще. Вы должны закодировать свою функцию, чтобы узнать, насколько она глубока, и завершить рекурсию, когда она становится слишком глубокой.

Причина того, что предел рекурсии по-разному применяется в вашей программе, а интерпретатор - потому, что у них разные вершины стека: функции, вызываемые в интерпретаторе, чтобы добраться до точки запуска вашего кода.

Ответ 2

В то время как несколько тангенциальный (я бы поставил его в комментарии, но я не думаю, что там место), следует отметить, что setrecursionlimit несколько вводит в заблуждение - он фактически устанавливает максимальную глубину стека:

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

Вот почему функция ведет себя по-разному в зависимости от того, откуда вы ее вызываете. Кроме того, если func2 должен был сделать вызов stdlib (или что-то еще), который в конечном итоге вызывал ряд функций, так что он добавлял больше N в стек, исключение запускалось бы раньше.

Кроме того, я бы тоже не изменил sys.tracebacklimit; это повлияет на остальную часть вашей программы. Идите с ответом Неда.

Ответ 3

игнорируя более общие проблемы, похоже, что вы можете получить текущую глубину кадра, просмотрев длину inspect.getouterframes(). что даст вам "нулевую точку", из которой вы можете установить ограничение глубины (отказ от ответственности: я этого не пробовал).

edit: или len (inspect.stack()) - мне непонятно, в чем разница. мне было бы интересно узнать, работает ли это, и были ли они другими.

Ответ 4

Я бы выбрал первый подход, он проще и объясняет сам. В конце концов, предел рекурсии - это ваш явный выбор, так зачем обфускации его?