递归函数定义简单,逻辑清晰,可以使用很少的代码实现较为复杂的功能。但是我们都知道,对于计算机来说,函数的调用都是通过栈(stack)来实现的。每当进行一次函数调用,栈就会增加一层栈帧,以实现函数跳转;每当函数调用结束返回时,栈就相应地减少一层栈帧。如果我们进行大量的递归调用,就会耗尽栈的有限的资源空间,造成栈溢出。
栈溢出是一种很危险的情况,导致的后果也很严重。我们要想办法保证,我们在进行函数递归调用时,不会造成这种情况。
尾递归优化可以在函数返回的时候,调用自身本身,并且,在return语句中不包含表达式,这样编译器或者解释器就可以吧尾递归进行优化。最后的结果是,不管递归函数进行多少次调用,都只占用一个栈帧,这样就可以避免栈溢出情况的出现。下面以一个简单的例子说明一下:
def fact(n): '''计算阶乘''' if n == 1: return 1 return n * fact(n - 1)
上面的代码是递归调用的一个经典使用,计算n的阶乘。假如n != 1,开始进入return计算语句,在表达式中递归调用fact()自身,一直到n == 1为止。假如n特别大,将有可能造成栈溢出。下面采用尾递归对上述程序进行优化:
def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product return fact_iter(num - 1, num * product)我们可以看到,fact_filter()函数的返回语句仅仅是返回递归函数本身,其参数num-1 和num * product在函数调用前就会被计算。每次产生变化的只是函数的参数,而不会发生无限的普通递归函数的调用,这样就可以解决栈溢出问题。