Python裝飾器結(jié)合遞歸原理解析
代碼如下:
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
對(duì)比代碼(把注釋的地方去掉后)的輸出:
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,) : 0 (1,) : 1 (2,) : 3 (0,) : 0 (1,) : 1 (2,) : 3 (3,) : 6 (0,) : 0 (1,) : 1 (2,) : 3 (3,) : 6 (4,) : 10 (0,) : 0 (1,) : 1 (2,) : 3 (3,) : 6 (4,) : 10 (5,) : 15 (0,) : 0 (1,) : 1 (2,) : 3 (3,) : 6 (4,) : 10 (5,) : 15 (6,) : 21 (0,) : 0 (1,) : 1 (2,) : 3 (3,) : 6 (4,) : 10 (5,) : 15 (6,) : 21 (7,) : 28 (0,) : 0 (1,) : 1 (2,) : 3 (3,) : 6 (4,) : 10 (5,) : 15 (6,) : 21 (7,) : 28 (8,) : 36 (0,) : 0 (1,) : 1 (2,) : 3 (3,) : 6 (4,) : 10 (5,) : 15 (6,) : 21 (7,) : 28 (8,) : 36 (9,) : 45 (0,) : 0 (1,) : 1 (2,) : 3 (3,) : 6 (4,) : 10 (5,) : 15 (6,) : 21 (7,) : 28 (8,) : 36 (9,) : 45 (10,) : 55
通過(guò)取消注釋的對(duì)比,可以得到如下結(jié)論:
- 裝飾器memoize實(shí)際上對(duì)于函數(shù)nsum()只執(zhí)行了第一次加載的時(shí)候的預(yù)處理,然后就是nsum = memoizer。
- 裝飾器的實(shí)質(zhì)是通過(guò)functools.wraps(fn)獲得函數(shù)的名字,便于nsum.__name__ ==nsum,并將參數(shù)傳至memoize(*args),也就是*args。
- 裝飾器通過(guò)memory(),和外面的裝飾器獲得的函數(shù),在內(nèi)部對(duì)函數(shù)進(jìn)行功能改造。在上例子中,通過(guò)known[args] = fn(*args)先執(zhí)行fn函數(shù),即上例子中nsum(10),然后就進(jìn)入遞歸,t同時(shí)調(diào)用memoizer()和nsum()函數(shù)10次,且先memoizer再nsum,而且每次都在``known[args] = fn(*args)`進(jìn)入遞歸,也就是每次nsum的執(zhí)行,故,對(duì)于為什么打印konwn中的元素是集中在一起的解釋就知道了,到了n == 0,才跳出遞歸,故,known的第一個(gè)元素是0,然后就循環(huán)往復(fù)。
- 最后,其實(shí),遞歸函數(shù)執(zhí)行的是fn(*args),即nsum()。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Django靜態(tài)文件配置request對(duì)象方法ORM操作講解
這篇文章主要為大家介紹了Django靜態(tài)文件配置request對(duì)象方法ORM操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Python中ValueError報(bào)錯(cuò)的原因和解決辦法
在Python編程中,ValueError是一種非常常見(jiàn)的異常類型,它通常發(fā)生在函數(shù)接收到一個(gè)有效類型但不適合該函數(shù)操作的值時(shí),本文將深入探討ValueError的報(bào)錯(cuò)原因、提供詳細(xì)的解決辦法,并通過(guò)豐富的代碼示例來(lái)加深理解,需要的朋友可以參考下2024-07-07tensorflow 1.X遷移至tensorflow2 的代碼寫(xiě)法
本文主要介紹了tensorflow 1.X遷移至tensorflow2 的代碼寫(xiě)法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12python切片復(fù)制列表的知識(shí)點(diǎn)詳解
在本篇文章里小編給大家整理的是一篇關(guān)于python切片復(fù)制列表的知識(shí)點(diǎn)相關(guān)內(nèi)容,有興趣的朋友們可以跟著學(xué)習(xí)下。2021-10-10python實(shí)現(xiàn)文本界面網(wǎng)絡(luò)聊天室
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)文本界面網(wǎng)絡(luò)聊天室,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12python實(shí)現(xiàn)在多維數(shù)組中挑選符合條件的全部元素
今天小編就為大家分享一篇python實(shí)現(xiàn)在多維數(shù)組中挑選符合條件的全部元素,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11用Python實(shí)現(xiàn)換行符轉(zhuǎn)換的腳本的教程
這篇文章主要介紹了用Python實(shí)現(xiàn)換行符轉(zhuǎn)換的腳本的教程,代碼非常簡(jiǎn)單,包括一個(gè)對(duì)操作說(shuō)明的功能的實(shí)現(xiàn),需要的朋友可以參考下2015-04-04Python實(shí)現(xiàn)識(shí)別圖像中人物的示例代碼
這篇文章主要介紹了通過(guò)face_recognition提供的demo代碼,簡(jiǎn)單調(diào)整了一下,從而實(shí)現(xiàn)識(shí)別圖像中人物的功能,感興趣的可以跟隨小編一起試試2022-01-01