python装饰器理解
1.装饰器的作用
在不修改被装饰对象的源代码以及调用方式的前提下为被装饰对象添加新功能
原则:
1.不修改被装饰对象的源代码
2.不修改被装饰对象的调用方式
目标:
为被装饰对象添加新功能
2.装饰器的定义和使用
来看下面的代码:
index函数的作用是程序在随机睡眠1到5秒之后,打印一句话
现在想为index函数添加一个新功能:统计index函数的运行时间,该怎么做呢??
修改index函数如下:
运行程序,执行结果如下:
welcome to index page
cost time: 2.000999927520752
可以看到,为index函数添加新功能确实实现了,但是却违反了开放封闭原则。
在符合开放封闭原则的前提下,如果想为index函数添加新功能,此时就要使用装饰器了
修改代码
运行程序,查看执行结果
welcome to index page
run time: 1.0
从程序执行结果可以看出,index函数的运行时间已经被统计出来了
但是查看源码可以知道,index函数的源码确实没有被修改,但是index的调用方式被修改了
而且还有一个问题就是,timmer这个装饰器只能被用来装饰index这个函数,如果以后想统计别的函数的运行时间,又要重新定义别的装饰器,这样也太不灵活了。
修改上面的代码
运行程序,查看程序执行结果
welcome to index page
run time: 4.0
可以看到,index函数的源代码没有被修改,index函数的调用方式也没有改变,但是依然为index函数添加了统计时间的功能,这里使用的就是装饰器了。
来分析下上面代码的执行流程:
这就是装饰器装饰index函数的执行流程
3.装饰器的简化使用
现在我又有另外一个函数home,现在我也想统计home函数的运行时间,可以把代码修改如下
运行程序,执行结果如下
welcome to index pagerun time: 3.0
welcome to home pagerun time: 4.0
可以看到,每次调用统计程序运行时间的装饰器timmer,都要先把被调用的函数的函数名作为参数传给timmer装饰器
然后再把timmer装饰器的执行结果赋值给被调用的函数名本身,最后才能调用被装饰的函数,太麻烦了有没有??
其实python中的装饰器可以简化成下面的格式
程序执行结果
welcome to index pagerun time: 2.0
welcome to home pagerun time: 4.0
可以看出,使用 @加装饰器名添加到被装饰对象的上方的方式也可以为一个函数添加装饰器中定义的功能
4.多个装饰器的定义与调用
在上面的例子里,定义并调用了一个统计程序运行时间的装饰器timmer,
如果现在想为index函数添加一个用户认证的功能,可以定义一个名为auth的装饰器
运行程序
从程序执行结果可以看出,用户登录密码验证的装饰器auth已经定义并被成功调用了
如果想为index函数添加用户认证的功能,又想统计index函数执行时间的功能,在使用装饰器的情况下该怎么调用呢
在上面的代码里,为index函数添加了两个装饰器,现在有一个问题,就是这两个装饰器究竟哪个先被调用,哪个后被调用呢??
来分析一下,
如果timmer装饰器先被调用,那么程序就会先执行timmer装饰器,然后再执行auth装饰器,提示输入用户名和密码,
这样一来timmer装饰器统计的时间就会包括输入用户名和密码的时间,这个时间会远远大于index函数睡眠的2秒种;
如果auth装饰器先被调用,timmer装饰器后被调用,那么timmer装饰器统计的运行时间就应该只包括index函数的执行时间值应该在2秒多一点点的时间范围内
运行程序,先输入错误的用户名和密码以使用程序的执行时间加长
从程序的执行结果可以知道,程序是先运行timmer装饰器,然后才运行auth装饰器,所以timmer统计的时间就包括了用户认证的时间,所以timmer统计到的程序运行时间远远大于index睡眠的2秒钟
所以这里得出一个结论:
当一个函数同时被两个装饰器装饰时,加上函数最上面的装饰器先执行,加在下面的装饰器先装饰
把上面例子里的timmer装饰器和auth装饰器位置互换一下
运行index函数,依然先输入错误的用户名和密码,增加用户认证的时间
可以看到,这次timmer统计到的时间只包含index函数的运行时间,不包含用户进行认证的时间
来分析一下上面例子中,index函数被timmer装饰器和auth装饰器装饰的代码装饰流程
在上面得出结论,一个函数同时被两个装饰器时,加在下面的装饰器先装饰
1.timmer装饰器装饰原始的index,可以写成:index=timmer(index)2.在timmer装饰器中,timmer装饰器实际上是返回inner的内存地址,所以在这里,index=inner3.timmer装饰器装饰完成后,由auth装饰器来装饰,此时可以写成index=auth(index),4.这里auth括号里的index已经不再是原始index函数,而是已经被timmer装饰过后的index了,所以index=auth(timmer(index))5.又因为timmer装饰的结果等于inner函数的内存地址,所以:index=auth(inner)
至此,两个装饰器的装饰过程已经知道了,来看程序的执行过程
所以这里用户输入用户名和密码的时间不会被timmer装饰器统计在内
5.被装饰函数参数的设置与定义
先来看一段代码
如上所示,home函数添加了一个参数,而index函数并没有参数
按照正常的函数的定义与调用方式,调用index函数和home函数的方式应该是下面这种形式
index()home("python")
然后我们运行程序就会发现,程序抛出了异常
说个异常说明inner函数不需要位置参数,但是我们给了一个位置参数
回到timmer装饰器定义的部分,可以看到,timmer装饰器的内部函数确实没有定义参数
这样一来,timmer装饰器只能用于装饰没有参数的函数了,
我们可以在timmer装饰器定义的时候为inner函数添加一个参数
但是这样一来,timmer装饰器装饰index函数的时候又会抛出异常,因为index函数没有参数
File "E:\python_learn\py_code\test.py", line 27, in <module>index()
TypeError: inner() missing 1 required positional argument: 'name'
在不知道被装饰函数的参数个数的情况下,即被装饰函数的参数可变长,且形式不固定的时候,
python装饰器理解的更多相关文章
- python 装饰器理解
简介 装饰器可以在不修改原有代码的基础上添加新的功能,可以将重复重用的代码抽取出来,进一步解耦,方便维护,一般适用于插入日志.性能测试.事务处理.缓存等 装饰器的前提 闭包 一般来说,当一个函数嵌套另 ...
- 关于python装饰器(Decorators)最底层理解的一句话
一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...
- 如何理解Python装饰器
如何理解Python装饰器?很多学员对此都有疑问,那么上海尚学堂python培训这篇文章就给予答复. 一.预备知识 首先要理解装饰器,首先要先理解在 Python 中很重要的一个概念就是:“函数是 F ...
- 转发对python装饰器的理解
[Python] 对 Python 装饰器的理解的一些心得分享出来给大家参考 原文 http://blog.csdn.net/sxw3718401/article/details/3951958 ...
- 理解 Python 装饰器看这一篇就够了
讲 Python 装饰器前,我想先举个例子,虽有点污,但跟装饰器这个话题很贴切. 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,让它 ...
- python 装饰器的理解以及类装饰器
python装饰器的作用就是在不改变原有函数结构的情况下给该函数增加一个新功能,就是不入侵到原来函数里面修改代码给其增加一个新功能 先看代码 def out(fn): def inner(*args, ...
- Python装饰器的通俗理解
转载:http://blog.csdn.net/u013471155 在学习Python的过程中,我相信有很多人和我一样,对Python的装饰器一直觉得很困惑,我也是困惑了好久,并通过思考和查阅才能略 ...
- (一)Python装饰器的通俗理解
在学习Python的过程中,我相信有很多人和我一样,对Python的装饰器一直觉得很困惑,我也是困惑了好久,并通过思考和查阅才能略有领悟,我希望以下的内容会对你有帮助,我也努力通过通俗的方式使得对Py ...
- 【Python】装饰器理解
以下文章转载自:点这里 关于装饰器相关的帖子记录在这里: 廖雪峰, thy专栏, stackflow Python的函数是对象 简单的例子: def shout(word="yes" ...
随机推荐
- Java多线程基础(一)
一个简单的多线程的例子: package multiThread; public class BasicThread implements Runnable{ private int countDow ...
- bzoj 4823: [Cqoi2017]老C的方块 [最小割]
4823: [Cqoi2017]老C的方块 题意: 鬼畜方块游戏不解释... 有些特殊边,有些四个方块组成的图形,方块有代价,删掉一些方块使得没有图形,最小化代价. 比较明显的最小割,一个图形中必须删 ...
- BZOJ 3456: 城市规划 [多项式求逆元 组合数学 | 生成函数 多项式求ln]
3456: 城市规划 题意:n个点组成的无向连通图个数 以前做过,今天复习一下 令\(f[n]\)为n个点的无向连通图个数 n个点的完全图个数为\(2^{\binom{n}{2}}\) 和Bell数的 ...
- c# 利用IMap 收取163邮件
最近我要做一个爬虫.这个爬虫需要如下几个步骤: 1 填写注册内容(需要邮箱注册) 2 过拖拽验证码(geetest) 3 注册成功会给邮箱发一封确认邮箱 4 点击确认邮箱中的链接 完成注册 我这里就采 ...
- Dagger2 使用全解析
Dagger2 使用全解析 Dagger是一个注入工具,何为注入,我们要生产一批机器人,每个机器人都有一个控制器,我们可以在机器人内部 new 出一个控制器: class Robot { val co ...
- hiveql函数笔记(二)
1.数据查询 //提高聚合的性能 SET hive.map.aggr=true; SELECT count(*),avg(salary) FROM employees; //木匾不允许在一个查询语句中 ...
- 阿里云ECS服务器上搭建keepalived+mha+mysql5.6+gtid+一主两从+脚本判断架构踩的坑
最近,公司项目搭建了一套后端数据库架构,不是在RDS,是在阿里云的ECS服务器上搭建keepalived.mha.mysql5.6.gtid.一主两从架构,目前还没有实现读写分离,以后架构升级,可能代 ...
- mysql之mysql_config_editor
本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn mysql_config_editor允许你把登录的身份验证信息存储 ...
- hexo博客简易搭建教程
什么是Hexo Hexo 是一个快速.简洁且高效的博客框架.Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页.官网 Hexo安装 安装 在安装Hex ...
- 03 JVM的垃圾回收机制
1.前言 理解JVM的垃圾回收机制(简称GC)有什么好处呢?作为一名软件开发者,满足自己的好奇心将是一个很好的理由,不过更重要的是,理解GC工作机制可以帮助你写出更好的Java程序. 在学习GC前,你 ...