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黑帽编程 3.4 跨越VLAN详解
Sep 28 Python
tensorflow获取变量维度信息
Mar 10 Python
Python 访问限制 private public的详细介绍
Oct 16 Python
详解如何用django实现redirect的几种方法总结
Nov 22 Python
python使用knn实现特征向量分类
Dec 26 Python
python处理大日志文件
Jul 23 Python
TensorFlow查看输入节点和输出节点名称方式
Jan 04 Python
TensorFlow学习之分布式的TensorFlow运行环境
Feb 05 Python
django xadmin action兼容自定义model权限教程
Mar 30 Python
Python @property及getter setter原理详解
Mar 31 Python
总结Python连接CS2000的详细步骤
Jun 23 Python
Django框架之路由用法
Jun 10 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--用万网的接口实现域名查询功能
2012/12/13 PHP
用php制作简单分页(从数据库读取记录)的方法详解
2013/05/04 PHP
使用PHP求两个文件的相对路径
2013/06/20 PHP
关于文本框的一些限制控制总结~~
2010/04/15 Javascript
加载jQuery后$冲突的解决办法
2010/07/09 Javascript
服务器端的JavaScript脚本 Node.js 使用入门
2012/03/07 Javascript
不使用XMLHttpRequest实现异步加载 Iframe和script
2012/10/29 Javascript
JQuery调用WebServices的方法和4个实例
2014/05/06 Javascript
javascript使用for循环批量注册的事件不能正确获取索引值的解决方法
2014/12/20 Javascript
jQuery判断元素上是否绑定了指定事件的方法
2015/03/17 Javascript
js插件设置innerHTML时在IE8下提示“未知运行时错误”解决方法
2015/04/25 Javascript
JS实现IE状态栏文字缩放效果代码
2015/10/24 Javascript
javascript每日必学之基础入门
2016/02/16 Javascript
一句jQuery代码实现返回顶部效果(简单实用)
2016/12/28 Javascript
jQuery实现select模糊查询(反射机制)
2017/01/14 Javascript
Angular2学习教程之TemplateRef和ViewContainerRef详解
2017/05/25 Javascript
Django使用多数据库的方法
2017/09/06 Javascript
原生JavaScript实现Ajax异步请求
2017/11/19 Javascript
Vuejs中使用markdown服务器端渲染的示例
2017/11/22 Javascript
用ES6的class模仿Vue写一个双向绑定的示例代码
2018/04/20 Javascript
从零开始封装自己的自定义Vue组件
2018/10/09 Javascript
利用jsonp解决js读取本地json跨域的问题
2018/12/11 Javascript
Vue Autocomplete 自动完成功能简单示例
2019/05/25 Javascript
微信小程序封装分享与分销功能过程解析
2019/08/13 Javascript
[36:33]2018DOTA2亚洲邀请赛 4.3 突围赛 EG vs Newbee 第二场
2018/04/04 DOTA
详解Python核心对象类型字符串
2018/02/11 Python
一条命令解决mac版本python IDLE不能输入中文问题
2018/05/15 Python
Python小工具之消耗系统指定大小内存的方法
2018/12/03 Python
德国汉莎航空中国官网: Lufthansa中国
2017/03/30 全球购物
Sneaker Studio罗马尼亚网站:购买运动鞋
2018/11/04 全球购物
学校安全防火方案
2014/06/07 职场文书
演讲稿开场白台词
2014/08/25 职场文书
财务个人年度总结范文
2015/02/26 职场文书
学困生转化工作总结
2015/08/13 职场文书
如何解决springcloud feign 首次调用100%失败的问题
2021/06/23 Java/Android
Redis集群节点通信过程/原理流程分析
2022/03/18 Redis