1. 程式人生 > >python 最大遞迴次數 RuntimeError: maximum recursion depth exceeded

python 最大遞迴次數 RuntimeError: maximum recursion depth exceeded

幫別人看程式碼,偶然遇到這個問題,原來python直譯器有一個預設的最大遞迴次數是999。

舉個例子:

def recursion(n):
    if (n <= 1):
        return
    print n
    recursion(n - 1)

print "test 999"
recursion(999)   #正常執行

print "test 1000"
recursion(1000)  #報錯,RuntimeError: maximum recursion depth exceeded
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可以在檔案初始位置修改這個最大遞迴次數,如下:

import
sys sys.setrecursionlimit(10000) # set the maximum depth as 10000
  • 1
  • 2
  • 3

這時候遞迴1000次,2000次都不會報錯了,但次數很大時比如5000就會報錯,又查資料,結論如下:

sys.setrecursionlimit(limit) 
Set the maximum depth of the Python interpreter stack to limit. This limit prevents infinite recursion from causing an overflow of the C stack and crashing Python. 
The highest possible limit is platform-dependent. A user may need to set the limit higher when she has a program that requires deep recursion and a platform that supports a higher limit. This should be done with care, because a too-high limit can lead to a crash.

sys.setrecursionlimit() 只是修改直譯器在解釋時允許的最大遞迴次數,此外,限制最大遞迴次數的還和作業系統有關,經過測試:

windows下最大迭代次數約4400次,linux下最大迭代次數約為24900次(python 2.7 64位)

如下程式碼可以測試最大迭代次數:


import sys
import itertools

class RecursiveBlowup1:
    def __init__(self):
        self.__init__()

def test_init():
    return RecursiveBlowup1()

class RecursiveBlowup2
:
def __repr__(self): return repr(self) def test_repr(): return repr(RecursiveBlowup2()) class RecursiveBlowup4: def __add__(self, x): return x + self def test_add(): return RecursiveBlowup4() + RecursiveBlowup4() class RecursiveBlowup5: def __getattr__(self, attr): return getattr(self, attr) def test_getattr(): return RecursiveBlowup5().attr class RecursiveBlowup6: def __getitem__(self, item): return self[item - 2] + self[item - 1] def test_getitem(): return RecursiveBlowup6()[5] def test_recurse(): return test_recurse() def test_cpickle(_cache={}): try: import cPickle except ImportError: print "cannot import cPickle, skipped!" return l = None for n in itertools.count(): try: l = _cache[n] continue # Already tried and it works, let's save some time except KeyError: for i in range(100): l = [l] cPickle.dumps(l, protocol=-1) _cache[n] = l def check_limit(n, test_func_name): sys.setrecursionlimit(n) if test_func_name.startswith("test_"): print test_func_name[5:] else: print test_func_name test_func = globals()[test_func_name] try: test_func() # AttributeError can be raised because of the way e.g. PyDict_GetItem() # silences all exceptions and returns NULL, which is usually interpreted # as "missing attribute". except (RuntimeError, AttributeError): pass else: print "Yikes!" limit = 1000 while 1: check_limit(limit, "test_recurse") # check_limit(limit, "test_add") # check_limit(limit, "test_repr") # check_limit(limit, "test_init") # check_limit(limit, "test_getattr") # check_limit(limit, "test_getitem") # check_limit(limit, "test_cpickle") print "Limit of %d is fine" % limit limit = limit + 100