这里有一个尾递归函数
def recursive_function(n, sum):
if n < 1:
return sum
else:
return recursive_function(n-1, sum+n)
c = 998
print(recursive_function(c, 0))
它一直工作到n=997,然后它就中断并抛出一个RecursionError:在比较中超过了最大递归深度。这只是一个堆栈溢出吗?有办法绕过它吗?
这里有一个尾递归函数
def recursive_function(n, sum):
if n < 1:
return sum
else:
return recursive_function(n-1, sum+n)
c = 998
print(recursive_function(c, 0))
它一直工作到n=997,然后它就中断并抛出一个RecursionError:在比较中超过了最大递归深度。这只是一个堆栈溢出吗?有办法绕过它吗?
当前回答
资源。Setrlimit还必须用于增加堆栈大小和防止段故障
Linux内核限制了进程的堆栈。
Python将局部变量存储在解释器的堆栈上,因此递归占用解释器的堆栈空间。
如果Python解释器试图超过堆栈限制,Linux内核会使其出现分段错误。
堆栈限制大小由getrlimit和setrlimit系统调用控制。
Python通过资源模块提供了对这些系统调用的访问。
sys。例如,https://stackoverflow.com/a/3323013/895245中提到的setrecursionlimit只增加了Python解释器自身对其堆栈大小的限制,但它不会触及Linux内核对Python进程施加的限制。
示例程序:
main.py
import resource
import sys
print resource.getrlimit(resource.RLIMIT_STACK)
print sys.getrecursionlimit()
print
# Will segfault without this line.
resource.setrlimit(resource.RLIMIT_STACK, [0x10000000, resource.RLIM_INFINITY])
sys.setrecursionlimit(0x100000)
def f(i):
print i
sys.stdout.flush()
f(i + 1)
f(0)
当然,如果你继续增加setrlimit,你的RAM最终会用完,这将使你的计算机由于疯狂的交换而变慢到停止,或者通过OOM杀手杀死Python。
在bash中,您可以使用以下命令查看并设置堆栈限制(单位为kb):
ulimit -s
ulimit -s 10000
我的默认值是8Mb。
参见:
在python脚本中设置stacksize Linux、Mac和Windows的硬递归限制是什么?
在Ubuntu 16.10, Python 2.7.12上测试。
其他回答
资源。Setrlimit还必须用于增加堆栈大小和防止段故障
Linux内核限制了进程的堆栈。
Python将局部变量存储在解释器的堆栈上,因此递归占用解释器的堆栈空间。
如果Python解释器试图超过堆栈限制,Linux内核会使其出现分段错误。
堆栈限制大小由getrlimit和setrlimit系统调用控制。
Python通过资源模块提供了对这些系统调用的访问。
sys。例如,https://stackoverflow.com/a/3323013/895245中提到的setrecursionlimit只增加了Python解释器自身对其堆栈大小的限制,但它不会触及Linux内核对Python进程施加的限制。
示例程序:
main.py
import resource
import sys
print resource.getrlimit(resource.RLIMIT_STACK)
print sys.getrecursionlimit()
print
# Will segfault without this line.
resource.setrlimit(resource.RLIMIT_STACK, [0x10000000, resource.RLIM_INFINITY])
sys.setrecursionlimit(0x100000)
def f(i):
print i
sys.stdout.flush()
f(i + 1)
f(0)
当然,如果你继续增加setrlimit,你的RAM最终会用完,这将使你的计算机由于疯狂的交换而变慢到停止,或者通过OOM杀手杀死Python。
在bash中,您可以使用以下命令查看并设置堆栈限制(单位为kb):
ulimit -s
ulimit -s 10000
我的默认值是8Mb。
参见:
在python脚本中设置stacksize Linux、Mac和Windows的硬递归限制是什么?
在Ubuntu 16.10, Python 2.7.12上测试。
我有一个类似的问题,错误“最大递归深度超过”。我发现这个错误是由我用os.walk循环遍历的目录中的一个损坏文件触发的。如果您在解决这个问题时遇到了困难,并且您正在使用文件路径,请务必缩小范围,因为它可能是一个损坏的文件。
我不确定我是不是在重复某人的意思但前段时间有人写了一个y算子用于递归调用函数
def tail_recursive(func):
y_operator = (lambda f: (lambda y: y(y))(lambda x: f(lambda *args: lambda: x(x)(*args))))(func)
def wrap_func_tail(*args):
out = y_operator(*args)
while callable(out): out = out()
return out
return wrap_func_tail
然后递归函数需要形式:
def my_recursive_func(g):
def wrapped(some_arg, acc):
if <condition>: return acc
return g(some_arg, acc)
return wrapped
# and finally you call it in code
(tail_recursive(my_recursive_func))(some_arg, acc)
对于斐波那契数,你的函数是这样的:
def fib(g):
def wrapped(n_1, n_2, n):
if n == 0: return n_1
return g(n_2, n_1 + n_2, n-1)
return wrapped
print((tail_recursive(fib))(0, 1, 1000000))
输出:
..684684301719893411568996526838242546875
(实际上是数字的音调)
看起来你只需要设置一个更高的递归深度:
import sys
sys.setrecursionlimit(1500)
编辑:6年后,我意识到我的“使用生成器”是轻率的,没有回答这个问题。我的歉意。
我想我的第一个问题是:你真的需要改变递归限制吗?如果不是,那么也许我的答案或其他不涉及改变递归限制的答案将适用。否则,如前所述,使用sys.getrecursionlimit(n)覆盖递归限制。
使用发电机?
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fibs = fib() #seems to be the only way to get the following line to work is to
#assign the infinite generator to a variable
f = [fibs.next() for x in xrange(1001)]
for num in f:
print num
以上fib()函数改编自Python生成器导论。