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