【Python学习笔记】一个很酷的尾递归优化

一般来说,Python、Java和C#是没有尾递归优化能力的。
用斐波那契数列举栗子

def Fib(n,b1=1,b2=1,c=3):
     if n<3:
         return 1
     else:
         if n==c:
             return b1+b2
         else:
             return Fib(n,b1=b2,b2=b1+b2,c=c+1)

用这段程序测试一下,Fib(1001)

>>> Fib(1001)
70330367711422815821835254877183549770181269836358732742604905087154537118196933579742249494562611733487750449241765991088186363265450223647106012053374121273867339111198139373125598767690091902245245323403501L

如果我们用1002进行测试,会出现以下结果

>>> Fib(1002)
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 8, in Fib
  File "", line 8, in Fib
  ...

  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
  File "", line 8, in Fib
RuntimeError: maximum recursion depth exceeded

嗝屁了。。。。

好了,现在我们来进行尾递归优化
我们给刚才的Fib()加上一个Decorator

@tail_call_optimized
def Fib(n,b1=1,b2=1,c=3):
     if n<3:         
         return 1     
     else:         
         if n==c:             
             return b1+b2         
         else:             
             return Fib(n,b1=b2,b2=b1+b2,c=c+1)

再进行以下1002的测试

>>> factorial(1002)
403595226631845209051880628629640843684504427553075197870696397761049187812849704911861525200847286953691029536005008041199679136947538974195145603806613764659598772448343155346099936257625753094803884027860163939789842138835459726309735765486625072922145181887975022572105212827325352650360822643468087741771243274550281589906300986381710232456423433251607344294784039373634656024124453620089721583696043568454453734050864695625360160060837985907843886863299796154720279007113956951303885722179881815749987309805714978843425686190000118314099658179076045908112174184036411692279009131566184678468723846725908145293854399345046411198447956200779858905167173352465714153538801211087720100276119910066915976203462207958828341534221899791288298092817195947660859191130400508223302612192464542972486137970999130314487401586333890803098965666729069983059073029836289064949751403828279759468153435153751780866336232529843901200433684288385627283533199027396434893357282086051585816529002990308480430936068459723972706109774049015004995093607154690663050562540125426199747069929118955699230774847071199289100876508706102549187041138413686787948205954112870737405031681121042921061995174289468425331650464561340409424173780188880812336110785337046525095105430858497742434742094044183974861014953066385473893642483322068557624990042622887596537142678944093257718557160897828029849892850965669582034472885502604911928460284005306342333130336198553219540604482194933412078382116571387810188247661856673784645931148063936059156551998852938063173052063949026304605205631624638774310744480832995609830297494545245656244455620251778253774769266089821112470989893912601073959708491868875645584730271480394263197569955225062667191096707656654407022887525790856785877899038650115933178051995456774627931040674690671748424144553319969406033752761076645509257674502108335781092379493678262981271954245666983743955528481743109188752583996172412523833843658095508570036882989691250736327439493831143034902758721795187227924667136887444201148357041223132757556636766608468460560883010885098435917684827483525679451551727590758306091652499677082687155106869995981028480229123981226964327190673310250990586533694909587495431670564164338201999882039484224426801780967555634548300999593123533545305689646564984159483631997655252944785081759776787922944000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000L

【得意脸】

好吧,这是我从国外的一个网上拉下来的。。。直接贴上

import sys    
class TailRecurseException:  
   def __init__(self, args, kwargs):  
     self.args = args  
     self.kwargs = kwargs  

def tail_call_optimized(g):   
   def func(*args, **kwargs):  
     f = sys._getframe()  
     if f.f_back and f.f_back.f_back and f.f_back.f_back.f_code == f.f_code:  
       raise TailRecurseException(args, kwargs)  
     else:  
       while 1:  
         try:  
           return g(*args, **kwargs)  
         except TailRecurseException, e:  
           args = e.args  
           kwargs = e.kwargs  
   func.__doc__ = g.__doc__  
   return func  

使用的方法前面已经展示了,令我感到大开眼界的是,作者用了抛出异常然后自己捕获的方式来打破调用栈的增长,简直是太匪夷所思了。而且效率问题,和直接尾递归Fib相比大概造成了五倍的时间开销。
最后很不可思议的,尾递归优化的目的达成了。

去膜拜作者吧,下面是出处:
http://code.activestate.com/recipes/474088/

你可能感兴趣的:(【Python学习笔记】一个很酷的尾递归优化)