Python装饰器结合递归原理解析


Posted in Python onJuly 02, 2020

代码如下:

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
pytyon 带有重复的全排列
Aug 13 Python
跟老齐学Python之集合(set)
Sep 24 Python
caffe binaryproto 与 npy相互转换的实例讲解
Jul 09 Python
CentOS 7下安装Python3.6 及遇到的问题小结
Nov 08 Python
详解python websocket获取实时数据的几种常见链接方式
Jul 01 Python
python操作openpyxl导出Excel 设置单元格格式及合并处理代码实例
Aug 27 Python
Python 通过截图匹配原图中的位置(opencv)实例
Aug 27 Python
基于Python共轭梯度法与最速下降法之间的对比
Apr 02 Python
使用darknet框架的imagenet数据分类预训练操作
Jul 07 Python
Django如何使用asyncio协程和ThreadPoolExecutor多线程
Oct 12 Python
Python list和str互转的实现示例
Nov 16 Python
Python 数据可视化之Matplotlib详解
Nov 02 Python
Python OpenCV读取中文路径图像的方法
Jul 02 #Python
keras.utils.to_categorical和one hot格式解析
Jul 02 #Python
python 使用多线程创建一个Buffer缓存器的实现思路
Jul 02 #Python
浅谈keras中的keras.utils.to_categorical用法
Jul 02 #Python
Python使用OpenPyXL处理Excel表格
Jul 02 #Python
解决keras GAN训练是loss不发生变化,accuracy一直为0.5的问题
Jul 02 #Python
解决keras,val_categorical_accuracy:,0.0000e+00问题
Jul 02 #Python
You might like
PHP实现货币换算的方法
2014/11/29 PHP
CodeIgniter删除和设置Cookie的方法
2015/04/07 PHP
解析PHP的Yii框架中cookie和session功能的相关操作
2016/03/17 PHP
[原创]PHP正则删除html代码中a标签并保留标签内容的方法
2017/05/23 PHP
javascript 自动转到命名锚记
2009/01/10 Javascript
面向对象的编程思想在javascript中的运用上部
2009/11/20 Javascript
js保存当前路径(cookies记录)
2010/12/14 Javascript
JavaScript 放大镜 移动镜片效果代码
2011/05/09 Javascript
Jquery解析json数据详解
2013/12/26 Javascript
js中使用replace方法完成某个字符的转换
2014/08/20 Javascript
加载列表时jquery获取ul中第一个li的属性
2014/11/02 Javascript
js实现图片漂浮效果的方法
2015/03/02 Javascript
jQuery form插件之formDdata参数校验表单及验证后提交
2016/01/23 Javascript
基于JS实现textarea中获取动态剩余字数的方法
2016/05/25 Javascript
jquery插件方式实现table查询功能的简单实例
2016/06/06 Javascript
深入理解JS实现快速排序和去重
2016/10/17 Javascript
全面解析vue中的数据双向绑定
2017/05/10 Javascript
IntersectionObserver实现图片懒加载的示例
2017/09/29 Javascript
微信小程序tabBar用法实例详解
2017/12/04 Javascript
Vue中使用vee-validate表单验证的方法
2018/05/09 Javascript
微信小程序scroll-view实现滚动穿透和阻止滚动的方法
2018/08/20 Javascript
[01:03]PWL开团时刻DAY6——别打我
2020/11/05 DOTA
PyMongo安装使用笔记
2015/04/27 Python
对Python3 * 和 ** 运算符详解
2019/02/16 Python
实例教程 纯CSS3打造非常炫的加载动画效果
2014/11/05 HTML / CSS
html5给汉字加拼音加进度条的实现代码
2020/04/07 HTML / CSS
DC Shoes官网:美国滑板鞋和服饰品牌
2017/09/03 全球购物
班主任个人工作反思
2014/04/28 职场文书
网吧消防安全责任书
2014/07/29 职场文书
2014年维稳工作总结
2014/11/18 职场文书
毕业典礼邀请函
2015/01/31 职场文书
中学政教处工作总结
2015/08/13 职场文书
餐厅营销的秘密:为什么老顾客会流水?
2019/08/08 职场文书
PhpSpreadsheet中文文档 | Spreadsheet操作教程实例
2021/04/01 PHP
python 逐步回归算法
2021/04/06 Python
mysql分组后合并显示一个字段的多条数据方式
2022/01/22 MySQL