Python裝飾器結合遞迴原理解析
阿新 • • 發佈:2020-07-03
程式碼如下:
import functools def memoize(fn): print('start memoize') known = dict() @functools.wraps(fn) def memoizer(*args): if args not in known: print('memorize %s'%args) # known[args] = fn(*args) for k in known.keys(): print('%s : %s'%(k,known[k]),end = ' ') print() # return known[args] return memoizer @memoize def nsum(n): print('now is %s'%n) assert (n >= 0),'n must be >= 0' return 0 if n == 0 else n + nsum(n - 1) @memoize def fibonacci(n): assert (n >= 0),'n must be >= 0' return n if n in (0,1) else fibonacci(n - 1) + fibonacci(n - 2) if __name__ == '__main__': print(nsum(10)) print(fibonacci(10))
輸出如下:
start memoize
start memoize
memorize 10None
memorize 10None
對比程式碼(把註釋的地方去掉後)的輸出:
start memoize start memoize memorize 10 now is 10 memorize 9 now is 9 memorize 8 now is 8 memorize 7 now is 7 memorize 6 now is 6 memorize 5 now is 5 memorize 4 now is 4 memorize 3 now is 3 memorize 2 now is 2 memorize 1 now is 1 memorize 0 now is 0 (0,) : 0 (0,) : 0 (1,) : 1 (0,) : 1 (2,) : 3 (0,) : 3 (3,) : 6 (0,) : 6 (4,) : 10 (0,) : 10 (5,) : 15 (0,) : 15 (6,) : 21 (0,) : 21 (7,) : 28 (0,) : 28 (8,) : 36 (0,) : 36 (9,) : 45 (0,) : 45 (10,) : 55
通過取消註釋的對比,可以得到如下結論:
- 裝飾器memoize實際上對於函式nsum()只執行了第一次載入的時候的預處理,然後就是nsum = memoizer。
- 裝飾器的實質是通過functools.wraps(fn)獲得函式的名字,便於nsum.__name__ ==nsum,並將引數傳至memoize(*args),也就是*args。
- 裝飾器通過memory(),和外面的裝飾器獲得的函式,在內部對函式進行功能改造。在上例子中,通過known[args] = fn(*args)先執行fn函式,即上例子中nsum(10),然後就進入遞迴,t同時呼叫memoizer()和nsum()函式10次,且先memoizer再nsum,而且每次都在``known[args] = fn(*args)`進入遞迴,也就是每次nsum的執行,故,對於為什麼列印konwn中的元素是集中在一起的解釋就知道了,到了n == 0,才跳出遞迴,故,known的第一個元素是0,然後就迴圈往復。
- 最後,其實,遞迴函式執行的是fn(*args),即nsum()。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。