匪夷所思 Python实现尾递归优化

开发 后端
一般来说,Python和Java、C#一样,是没有尾递归自动优化的能力的,但本文将给大家介绍如何使用Python来实现尾递归优化,希望给大家以启示。

一般来说,Python和Java、C#一样,是没有尾递归自动优化的能力的,递归调用受到调用栈长度的限制被广泛的诟病,但本文将给大家一个匪夷所思的方法,来实现Python的尾递归优化,因此Python的递归调用再也不用受到调用栈长度的制约。

51CTO推荐阅读:使用Python递归对文件进行相关处理

先来看尾递过方式的调用:

  1. defFib(n,b1=1,b2=1,c=3):  
  2. ifn<3: 
  3. return1  
  4. else:  
  5. ifn==c:  
  6. returnb1+b2  
  7. else:  
  8. returnFib(n,b1=b2,b2=b1+b2,cc=c+1) 

这段程序我们来测试一下,调用Fib(1001)结果:

  1. >>>defFib(n,b1=1,b2=1,c=3):  
  2. ...ifn<3: 
  3. ...return1  
  4. ...else:  
  5. ...ifn==c:  
  6. ...returnb1+b2  
  7. ...else:  
  8. ...returnFib(n,b1=b2,b2=b1+b2,cc=c+1)  
  9. ...  
  10. >>>Fib(1001)  
  11.  
  12. 703303677114228158218352548771835497701812698363587327426  
  13. 049050871545371181969335797422494945626117334877504492417  
  14. 659910881863632654502236471060120533741212738673391111981  
  15. 39373125598767690091902245245323403501L 

如果我们用Fib(1002),结果如下:

  1. .....  
  2. File"<stdin>",line8,inFib  
  3. File"<stdin>",line8,inFib  
  4. File"<stdin>",line8,inFib  
  5. File"<stdin>",line8,inFib  
  6. File"<stdin>",line8,inFib  
  7. File"<stdin>",line8,inFib  
  8. RuntimeError:maximumrecursiondepthexceeded 

现在我们来尾递归优化。我们给刚才的Fib函数增加一个Decorator,如下:

  1. @tail_call_optimized  
  2. defFib(n,b1=1,b2=1,c=3):  
  3. ifn<3: 
  4. return1  
  5. else:  
  6. ifn==c:  
  7. returnb1+b2  
  8. else:  
  9. returnFib(n,b1=b2,b2=b1+b2,cc=c+1) 

就是这个@tail_call_optimized的装饰器,这个装饰器使Python神奇的打破了调用栈的限制。这下即使我们Fib(20000),也能在780ms跑出结果。

  1. importsys  
  2. classTailRecurseException:  
  3. def__init__(self,args,kwargs):  
  4. self.args=args  
  5. self.kwargs=kwargs  
  6. deftail_call_optimized(g):  
  7. """  
  8. Thisfunctiondecoratesafunctionwithtailcall  
  9. optimization.Itdoesthisbythrowinganexception  
  10. ifitisit'sowngrandparent,andcatchingsuch  
  11. exceptionstofakethetailcalloptimization.  
  12.  
  13. Thisfunctionfailsifthedecorated  
  14. functionrecursesinanon-tailcontext.  
  15. """  
  16. deffunc(*args,**kwargs):  
  17. f=sys._getframe()  
  18. iff.f_backandf.f_back.f_backandf.f_back.f_back.f_code==f.f_code:  
  19. raiseTailRecurseException(args,kwargs)  
  20. else:  
  21. while1:  
  22. try:  
  23. returng(*args,**kwargs)  
  24. exceptTailRecurseException,e:  
  25. args=e.args  
  26. kwargs=e.kwargs  
  27. func.__doc__=g.__doc__  
  28. returnfunc 

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

原文链接:http://www.cnblogs.com/Alexander-Lee/archive/2010/09/16/1827587.html

【编辑推荐】

  1. Python闭包的概念、形式与应用
  2. Python自动单元测试框架的应用详解
  3. 旁观者清 Python与Ruby各有千秋
  4. 手把手教您Python多线程应用技巧
  5. 加速程序开发 Python整合C语言模块
责任编辑:王晓东 来源: 博客园
相关推荐

2018-11-20 14:48:54

2020-05-27 07:38:36

尾递归优化递归函数

2016-11-17 16:01:21

dagger2android

2009-03-21 15:09:32

Nehalem服务器Intel

2012-09-04 09:55:22

代码抓狂的代码开发

2018-01-31 09:25:39

2009-09-17 09:10:53

阿里马云

2011-06-03 12:38:05

GeekApp

2020-10-10 09:08:51

数据中心

2020-09-30 08:07:46

如何优化尾调用

2009-07-22 07:44:00

Scala尾递归

2019-03-26 08:15:45

iOS尾调用Objective-C

2021-03-24 10:00:32

Python递归函数Python基础

2021-03-09 10:12:28

编程技能开发

2021-10-08 09:07:09

算法程序技术

2017-09-14 09:40:32

PythonUbuntu信号机制

2020-11-02 07:12:27

程序员上级领导管理

2012-02-22 14:12:08

算法

2023-12-25 09:19:00

AI英伟达研究

2020-01-18 19:28:33

微软Windows 10浏览器
点赞
收藏

51CTO技术栈公众号