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代码
Mar 13 Python
Python中为feedparser设置超时时间避免堵塞
Sep 28 Python
python获取当前运行函数名称的方法实例代码
Apr 06 Python
Python3实现发送QQ邮件功能(html)
Dec 15 Python
对pandas中apply函数的用法详解
Apr 10 Python
Tensorflow卷积神经网络实例
May 24 Python
Python for循环中的陷阱详解
Jul 13 Python
详解Python3中setuptools、Pip安装教程
Jun 18 Python
python time.sleep()是睡眠线程还是进程
Jul 09 Python
Python编译为二进制so可执行文件实例
Dec 23 Python
Jupyter安装拓展nbextensions及解决官网下载慢的问题
Mar 03 Python
68行Python代码实现带难度升级的贪吃蛇
Jan 18 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 采集程序 常用函数
2008/12/18 PHP
PHP的PSR规范中文版
2013/09/28 PHP
Yii2框架使用计划任务的方法
2016/05/25 PHP
PHP设计模式之PHP迭代器模式讲解
2019/03/22 PHP
[原创]js与自动伸缩图片 自动缩小图片的多浏览器兼容的方法总结
2007/03/12 Javascript
在IE,Firefox,Safari,Chrome,Opera浏览器上调试javascript
2008/12/02 Javascript
jQuery Select(单选) 模拟插件 V1.3.62 改进版
2010/07/17 Javascript
javascript遍历控件实例详细解析
2014/01/10 Javascript
编写自己的jQuery提示框(Tip)插件
2015/02/05 Javascript
javascript获取本机操作系统类型的方法
2015/08/13 Javascript
js判断手机浏览器操作系统和微信浏览器的方法
2016/04/30 Javascript
jQuery实现响应鼠标事件的图片透明效果【附demo源码下载】
2016/06/16 Javascript
Bootstrap入门教程一Hello Bootstrap初识
2017/03/02 Javascript
JS设计模式之观察者模式实现实时改变页面中金额数的方法
2018/02/05 Javascript
详解如何配置vue-cli3.0的vue.config.js
2018/08/23 Javascript
vue2中,根据list的id进入对应的详情页并修改title方法
2018/08/24 Javascript
微信小程序时间戳转日期的详解
2019/04/30 Javascript
实现高性能javascript的注意事项
2019/05/27 Javascript
Vue中component标签解决项目组件化操作
2020/09/04 Javascript
vue打开新窗口并实现传参的图文实例
2021/03/04 Vue.js
[01:41]DOTA2 2015国际邀请赛中国区预选赛第三日战报
2015/05/28 DOTA
Python中音频处理库pydub的使用教程
2017/06/07 Python
Python如何通过subprocess调用adb命令详解
2017/08/27 Python
Django实现简单分页功能的方法详解
2017/12/05 Python
Python数据结构与算法之常见的分配排序法示例【桶排序与基数排序】
2017/12/15 Python
Python基于Logistic回归建模计算某银行在降低贷款拖欠率的数据示例
2019/01/23 Python
python程序变成软件的实操方法
2019/06/24 Python
浅析HTML5 Landmark
2020/09/11 HTML / CSS
世界上最大的二手相机店:KEN
2017/05/17 全球购物
大学总结自我鉴定
2014/01/18 职场文书
2014学雷锋活动总结
2014/03/09 职场文书
关于国庆节的演讲稿
2014/09/05 职场文书
党员个人剖析材料
2014/09/30 职场文书
解决Nginx 配置 proxy_pass 后 返回404问题
2021/03/31 Servers
PyTorch中的torch.cat简单介绍
2022/03/17 Python
JS轻量级函数式编程实现XDM二
2022/06/16 Javascript