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 相关文章推荐
使用C语言来扩展Python程序和Zope服务器的教程
Apr 14 Python
浅谈MySQL中的触发器
May 05 Python
Python中几种导入模块的方式总结
Apr 27 Python
python中selenium操作下拉滚动条的几种方法汇总
Jul 14 Python
Python实现RGB与HSI颜色空间的互换方式
Nov 27 Python
python Opencv计算图像相似度过程解析
Dec 03 Python
jupyter 导入csv文件方式
Apr 21 Python
Python常用数字处理基本操作汇总
Sep 10 Python
Python全局变量与global关键字常见错误解决方案
Oct 05 Python
python利用xlsxwriter模块 操作 Excel
Oct 14 Python
Python调用ffmpeg开源视频处理库,批量处理视频
Nov 16 Python
python requests库的使用
Jan 06 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模板之Phpbean的目录结构
2008/01/10 PHP
PHP链表操作简单示例
2016/10/15 PHP
php array_walk 对数组中的每个元素应用用户自定义函数详解
2016/11/18 PHP
python进程与线程小结实例分析
2018/11/11 PHP
JavaScript 继承详解(三)
2009/07/13 Javascript
javascript开发技术大全-第1章javascript概述
2011/07/03 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图
2013/01/23 Javascript
jquery 动态创建元素的方式介绍及应用
2013/04/21 Javascript
javascript中负数算术右移、逻辑右移的奥秘探索
2013/10/17 Javascript
使用js画图之饼图
2015/01/12 Javascript
jQuery实现3D文字特效的方法
2015/03/10 Javascript
JavaScript实现同一页面内两个表单互相传值的方法
2015/08/12 Javascript
详细分析Javascript中创建对象的四种方式
2016/08/17 Javascript
JS设置CSS样式的方式汇总
2017/01/21 Javascript
jQuery is not defined 错误原因与解决方法小结
2017/03/19 Javascript
vue分类筛选filter方法简单实例
2017/03/30 Javascript
JS原生轮播图的简单实现(推荐)
2017/07/22 Javascript
微信小程序使用gitee进行版本管理
2018/09/20 Javascript
vue的keep-alive中使用EventBus的方法
2019/04/23 Javascript
jquery.tagsinput.js实现记录checkbox勾选的顺序
2019/09/21 jQuery
[54:57]DOTA2-DPC中国联赛定级赛 Aster vs DLG BO3第二场 1月8日
2021/03/11 DOTA
使用Python编写基于DHT协议的BT资源爬虫
2016/03/19 Python
Python设计模式之工厂模式简单示例
2018/01/09 Python
Python重新加载模块的实现方法
2018/10/16 Python
快速解决vue.js 模板和jinja 模板冲突的问题
2019/07/26 Python
keras做CNN的训练误差loss的下降操作
2020/06/22 Python
Nike爱尔兰官方网站:Nike.com (IE)
2018/03/12 全球购物
市场安全管理制度
2014/01/26 职场文书
淘宝好评语大全
2014/05/05 职场文书
大学英语专业求职信
2014/06/21 职场文书
乡文化站暑期培训方案
2014/08/28 职场文书
手机被没收的检讨书
2014/10/04 职场文书
辞职信的写法
2015/02/27 职场文书
出国留学单位推荐信
2015/03/26 职场文书
2015年体检中心工作总结
2015/05/27 职场文书
vue生命周期钩子函数以及触发时机
2022/04/26 Vue.js