Python具有最大递归深度,但没有最大迭代深度.为什么递归受限制?像迭代这样处理递归是不是更自然,而不是限制递归调用的数量?
我只想说这个问题的根源来自于尝试实现流(有关流的更多详细信息,请参阅this question).例如,假设我们要编写一个流来生成自然数:
def stream_accum(s, n): # force the stream to a list of length n
def loop(s, acc):
if len(acc) == n:
return acc
hd, tl = s()
return loop(tl, acc + [hd])
return loop(s, [])
def nats():
def loop(n):
return n, lambda: loop(n+1)
return loop(1)
流的递归定义非常吸引人.但是,我想更好/更pythonic的方法是使用发电机.
解决方法:
这里实际上有一些问题.
首先,正如NPE’s answer很好地解释的那样,Python并没有消除尾部调用,因此许多允许在Scheme中进行无限递归的函数在Python中是有限的.
其次,正如NPE所解释的那样,无法消除的调用会占用调用堆栈上的空间.而且,即使在执行TCE的语言中,也有许多递归函数无法像迭代那样对待. (考虑递归调用自身两次的天真Fibonacci函数.)
但是为什么调用堆栈首先是有限的资源? Python堆栈帧至少原则上可以在堆上实现并链接在一起(参见Stackless以获得该原理的存在证明),并且在64位存储器空间中,可以存在超过1000个堆栈帧的空间. (实际上,即使是几乎所有现代平台上的C堆栈都可以容纳超过1000个递归Python解释器调用.)
部分原因是历史性的:股票Python解释器使用固定的C堆栈在您进行递归调用时递归调用自身,并且它最初设计用于32位(甚至24位或20位)平台,其中C堆栈非常小.
但这可能已经改变了,Python 3.0将是一个改变它的完美场所.那么,他们为什么不呢?因为他们做出了有意识的语言设计决定.在Pythonic代码中,递归通常非常浅(例如,遍历浅树结构的os.walk代码);如果你的功能达到1000附近的任何深度,它更可能是一个错误,而不是故意的.所以,限制仍然存在.当然这有点循环 – 如果他们删除了限制(特别是,如果他们消除了尾部调用),更深层次的递归将变得更加惯用.但这就是重点 – 圭多不想要一种语言,其中深度递归是惯用的. (并且大多数Python社区都同意.)
标签:python,recursion,stack