Python装饰器结合递归原理解析
代码如下:
importfunctools defmemoize(fn): print('startmemoize') known=dict() @functools.wraps(fn) defmemoizer(*args): ifargsnotinknown: print('memorize%s'%args) #known[args]=fn(*args) forkinknown.keys(): print('%s:%s'%(k,known[k]),end='') print() #returnknown[args] returnmemoizer @memoize defnsum(n): print('nowis%s'%n) assert(n>=0),'nmustbe>=0' return0ifn==0elsen+nsum(n-1) @memoize deffibonacci(n): assert(n>=0),'nmustbe>=0' returnnifnin(0,1)elsefibonacci(n-1)+fibonacci(n-2) if__name__=='__main__': print(nsum(10)) print(fibonacci(10))
输出如下:
startmemoize
startmemoize
memorize10None
memorize10None
对比代码(把注释的地方去掉后)的输出:
startmemoize startmemoize memorize10 nowis10 memorize9 nowis9 memorize8 nowis8 memorize7 nowis7 memorize6 nowis6 memorize5 nowis5 memorize4 nowis4 memorize3 nowis3 memorize2 nowis2 memorize1 nowis1 memorize0 nowis0 (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
通过取消注释的对比,可以得到如下结论:
- 装饰器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()。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。