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使用mailbox打印电子邮件的方法
Apr 30 Python
详解Python中的Descriptor描述符类
Jun 14 Python
利用Python实现图书超期提醒
Aug 02 Python
Windows 64位下python3安装nltk模块
Sep 19 Python
对python指数、幂数拟合curve_fit详解
Dec 29 Python
pandas DataFrame行或列的删除方法的实现示例
Aug 02 Python
Python爬虫 批量爬取下载抖音视频代码实例
Aug 16 Python
Python 使用 Pillow 模块给图片添加文字水印的方法
Aug 30 Python
Python面向对象魔法方法和单例模块代码实例
Mar 25 Python
python输入一个水仙花数(三位数) 输出百位十位个位实例
May 03 Python
python re模块常见用法例举
Mar 01 Python
Python读取和写入Excel数据
Apr 20 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伪静态的实现详细介绍
2013/04/28 PHP
ThinkPHP连接数据库及主从数据库的设置教程
2014/08/22 PHP
php for 循环使用的简单实例
2016/06/02 PHP
PHP常用操作类之通信数据封装类的实现
2017/07/16 PHP
PHP基于redis计数器类定义与用法示例
2018/02/08 PHP
thinkPHP5框架中widget的功能与用法详解
2018/06/11 PHP
thinkPHP3.2使用RBAC实现权限管理的实现
2019/08/27 PHP
Extjs中DisplayField的日期或者数字格式化扩展
2010/09/03 Javascript
JavaScript去除空格的三种方法(正则/传参函数/trim)
2013/02/06 Javascript
使用jQuery内容过滤选择器选择元素实例讲解
2013/04/18 Javascript
js+css实现的简单易用兼容好的分页
2013/12/30 Javascript
js实现仿阿里巴巴城市选择框效果实例
2015/06/24 Javascript
javascript中mouseover、mouseout使用详解
2015/07/19 Javascript
JavaScript判断按钮被点击的方法
2015/12/13 Javascript
Vue.js实现实例搜索应用功能详细代码
2017/08/24 Javascript
Vue实现typeahead组件功能(非常靠谱)
2017/08/26 Javascript
Vue仿手机qq的实例代码(demo)
2017/09/08 Javascript
vue2 mint-ui loadmore实现下拉刷新,上拉更多功能
2018/03/21 Javascript
vue-cli 引入、配置axios的方法
2018/05/08 Javascript
vue中使用cookies和crypto-js实现记住密码和加密的方法
2018/10/18 Javascript
[01:14:30]TNC vs VG 2019国际邀请赛淘汰赛 胜者组赛BO3 第二场 8.20.mp4
2019/08/22 DOTA
[42:20]Secret vs Liquid 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
python发送邮件脚本
2018/05/22 Python
Python中asyncio与aiohttp入门教程
2018/10/16 Python
python利用小波分析进行特征提取的实例
2019/01/09 Python
Python实现FTP弱口令扫描器的方法示例
2019/01/31 Python
Django中使用极验Geetest滑动验证码过程解析
2019/07/31 Python
python中字典按键或键值排序的实现代码
2019/08/27 Python
分享PyCharm的几个使用技巧
2019/11/10 Python
英国布鲁姆精品店:Bloom Boutique
2018/03/01 全球购物
Nike法国官方网站:Nike.com FR
2018/07/22 全球购物
锦旗标语大全
2014/06/23 职场文书
三八活动策划方案
2014/08/17 职场文书
七年级上册语文教学计划
2015/01/22 职场文书
2015年信息技术教研组工作总结
2015/07/22 职场文书
详解在OpenCV中如何使用图像像素
2022/03/03 Python