python 最大遞迴次數 RuntimeError: maximum recursion depth exceeded
阿新 • • 發佈:2019-02-02
幫別人看程式碼,偶然遇到這個問題,原來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