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 相关文章推荐
python读取word文档的方法
May 09 Python
python 根据pid杀死相应进程的方法
Jan 16 Python
Python中Django 后台自定义表单控件
Mar 28 Python
python中for循环输出列表索引与对应的值方法
Nov 07 Python
对python 多线程中的守护线程与join的用法详解
Feb 18 Python
Python + OpenCV 实现LBP特征提取的示例代码
Jul 11 Python
Python中join()函数多种操作代码实例
Jan 13 Python
python爬虫实现POST request payload形式的请求
Apr 30 Python
520使用Python实现“我爱你”表白
May 20 Python
如何Tkinter模块编写Python图形界面
Oct 14 Python
使用django自带的user做外键的方法
Nov 30 Python
python生成word合同的实例方法
Jan 12 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
使用HMAC-SHA1签名方法详解
2013/06/26 PHP
php生成N个不重复的随机数实例
2013/11/12 PHP
Yii调试SQL的常用方法
2014/07/09 PHP
Laravel框架数据库CURD操作、连贯操作总结
2014/09/03 PHP
PHP的消息通信机制测试实例
2016/11/10 PHP
PHP面向对象程序设计之类与反射API详解
2016/12/02 PHP
Centos7安装swoole扩展操作示例
2020/03/26 PHP
在IE上直接编辑网页内容的js代码(IE地址栏js)
2009/04/27 Javascript
20个非常有用的PHP类库 加速php开发
2010/01/15 Javascript
Jquery上传插件 uploadify v3.1使用说明
2012/06/18 Javascript
JS动态创建Table,Tr,Td并赋值的具体实现
2013/07/05 Javascript
jquery高级编程的最佳实践详解
2014/03/23 Javascript
jQuery $.each遍历对象、数组用法实例
2015/04/16 Javascript
WordPress中利用AJAX异步获取评论用户头像的方法
2016/01/08 Javascript
Bootstrap每天必学之弹出框(Popover)插件
2016/04/25 Javascript
jQuery使用中可能被XSS攻击的一些危险环节提醒
2016/05/24 Javascript
微信小程序 倒计时组件实现代码
2016/10/24 Javascript
js实现截图保存图片功能的代码示例
2017/02/16 Javascript
jQuery Easyui Treegrid实现显示checkbox功能
2017/08/08 jQuery
javascript与PHP动态往类中添加方法对比
2018/03/21 Javascript
layui获取多选框中的值方法
2018/08/15 Javascript
Nuxt.js实现一个SSR的前端博客的示例代码
2019/09/06 Javascript
js实现简单页面全屏
2019/09/17 Javascript
解决vuex数据异步造成初始化的时候没值报错问题
2019/11/13 Javascript
基于ts的动态接口数据配置的详解
2019/12/18 Javascript
[01:05:40]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS DT第三场
2014/05/24 DOTA
Pytorch之Variable的用法
2019/12/31 Python
pytorch实现CNN卷积神经网络
2020/02/19 Python
Draper James官网:知名演员瑞茜·威瑟斯彭所创品牌
2017/10/25 全球购物
JRE、JDK、JVM之间的关系怎样
2012/05/16 面试题
Servlet的实例是在生命周期什么时候创建的?配置servlet最重要的是什么?
2012/05/30 面试题
人事专员工作职责
2014/02/22 职场文书
青年标兵事迹材料
2014/08/16 职场文书
三八妇女节标语
2014/10/09 职场文书
开工典礼致辞
2015/07/29 职场文书
CSS 实现角标效果的完整代码
2022/06/28 HTML / CSS