1. 程式人生 > 程式設計 >Python裝飾器結合遞迴原理解析

Python裝飾器結合遞迴原理解析

程式碼如下:

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 10

None
memorize 10

None

對比程式碼(把註釋的地方去掉後)的輸出:

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()。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。