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

本文探讨了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 "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  ...

  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", line 8, in Fib
  File "<stdin>", 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/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值