【Python學習筆記】一個很酷的尾遞迴優化
阿新 • • 發佈:2019-01-05
一般來說,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相比大概造成了五倍的時間開銷。
最後很不可思議的,尾遞迴優化的目的達成了。