python基础(8)-装饰器函数&进阶
从小例子进入装饰器
统计一个函数执行耗时
原始版本
import time # time模块有提供时间相关函数 def do_something(): print("do_something") time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时 start = time.time() do_something() print(time.time() - start) #result: # do_something # 0.5000283718109131问题:上述代码可以完成这个功能,但之后会发现,如果我们要统计其它函数,就必须在每个函数前后加入相应代码
装饰器版本1(无参数)
import time def execute_time(func): def inner(): start = time.time() func() print(time.time() - start) return inner # time模块有提供时间相关函数 def do_something(): print("do_something") time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时 do_something = execute_time(do_something) do_something() #result: # do_something # 0.5000283718109131从上述代码可以看到,使用了另一个函数execute_time()给我们要统计耗时的函数进行了包装,这时,这个execute_time()函数就叫做装饰器函数,而我们要统计的那个函数也就是do_something()函数就是被装饰的函数.问题:函数执行的时候实际上是调用的execute_time()函数中的inner()函数,这种方法虽然解决了原始版本的问题,但是当我们要统计的函数拥有返回值的时候,这时候我们获取不到返回值.
装饰器版本2(有固定参数)
import time def execute_time(func): def inner(do): start = time.time() result = func(do) print(time.time() - start) return result return inner # time模块有提供时间相关函数 def do_something(do): print("do_something", do) time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时 return 'do_something over' do_something = execute_time(do_something) print(do_something('say hello')) # result: # do_something say hello # 0.5000283718109131 # do_something over为了解决装饰器版本1的问题,我在inner()函数里面加了个返回值.问题:当被装饰函数的参数个数与inner()参数个数不同时,这个装饰器就不适用了
装饰器版本3(动态参数)
import time def execute_time(func): def inner(*args, **kwargs): start = time.time() result = func(*args, **kwargs) print(time.time() - start) return result return inner # time模块有提供时间相关函数 def do_something(do1,do2): print("do_something", do1,do2) time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时 return 'do_something over' do_something = execute_time(do_something) print(do_something('say hello1','say hello2')) # result: # do_something say hello1 say hello2 # 0.5000283718109131 # do_something over在第七天内容中有个知识点是动态参数,刚好可以解决这个问题
终极版本(语法糖@)
import time def execute_time(func): def inner(*args, **kwargs): start = time.time() result = func(*args, **kwargs) print(time.time() - start) return result return inner @execute_time def do_something(do1,do2): print("do_something", do1,do2) time.sleep(0.5) # 让程序停止0.5秒模拟其它操作耗时 return 'do_something over' # do_something = execute_time(do_something) print(do_something('say hello1','say hello2')) # result: # do_something say hello1 say hello2 # 0.5000283718109131 # do_something over对于装饰器,python内部给我们提供了语法糖支持.在需要被装饰的函数名上部使用[@装饰器函数名称]即可,简化上述代码18行
装饰器进阶
获取被包装函数原生属性
例1:常规函数取函数名
def func(): print('执行中') print(func.__name__) func() # result: # 执行中 # func常规函数可以通过函数的__name__属性可拿到当前函数名称
例2:被装饰函数取函数名
def wrapper(func): def inner(): print('执行前') result = func() print('执行后') return result return inner; @wrapper def func(): print('执行中') print(func.__name__) func() # result: # 执行前 # 执行中 # inner # 执行后问题:通过执行结果会发现,结果中想获取的函数名是func,而实际结果是inner.原因是@wrapper进行包装相当于执行一个操作:func=wrapper(func)=inner
解决
使用functools模块
from functools import wraps def wrapper(func): @wraps(func) def inner(): print('执行前') result = func() print('执行后') return result return inner; @wrapper def func(): print('执行中') print(func.__name__) func() # result: # 执行前 # 执行中 # func # 执行后导入functools模块后通过第4行操作,会发现执行的函数即使被包装但还是能获取到它本身的属性
带参数的装饰器
例1
def wrapper(func): def inner(): print('执行前') result = func() print('执行后') return result return inner; @wrapper def func_1(): print('执行中') @wrapper def func_2(): print('执行中') @wrapper def func_3(): print('执行中') ... @wrapper def func_n(): print('执行中')问题:通过上述代码会发现,有很多函数都用了同一个装饰器,如果有一天要取消这些函数上的装饰,就必须对每一个函数进行修改
解决
定义一个全局变量flag,并给原本装饰器外部再加一层函数用来接收参数,inner()函数内部通过外部参数flag判断被装饰函数的执行与否,修改flag即可控制装饰器的执行结果,如下:
from functools import wraps flag = True def wrapper_out(flag): def wrapper(func): @wraps(func) def inner(): if (flag): print('{}执行前'.format(func.__name__)) result = func() print('{}执行后'.format(func.__name__)) else: result = func() return result return inner return wrapper @wrapper_out(flag) def func_1(): print('{}执行中'.format(func_1.__name__)) @wrapper_out(flag) def func_2(): print('{}执行中'.format(func_2.__name__)) @wrapper_out(flag) def func_3(): print('{}执行中'.format(func_3.__name__)) ... @wrapper_out(flag) def func_n(): print('{}执行中'.format(func_n.__name__)) func_1() func_2() func_3() func_n() #result: # func_1执行前 # func_1执行中 # func_1执行后 # func_2执行前 # func_2执行中 # func_2执行后 # func_3执行前 # func_3执行中 # func_3执行后 # func_n执行前 # func_n执行中 # func_n执行后from functools import wraps flag = False def wrapper_out(flag): def wrapper(func): @wraps(func) def inner(): if (flag): print('{}执行前'.format(func.__name__)) result = func() print('{}执行后'.format(func.__name__)) else: result = func() return result return inner return wrapper @wrapper_out(flag) def func_1(): print('{}执行中'.format(func_1.__name__)) @wrapper_out(flag) def func_2(): print('{}执行中'.format(func_2.__name__)) @wrapper_out(flag) def func_3(): print('{}执行中'.format(func_3.__name__)) ... @wrapper_out(flag) def func_n(): print('{}执行中'.format(func_n.__name__)) func_1() func_2() func_3() func_n() #result: # func_1执行中 # func_2执行中 # func_3执行中 # func_n执行中
多个装饰器装饰同一个函数
代码
def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper1 @wrapper2 def f(): print('in f') f() # result: # wrapper1 ,before func # wrapper2 ,before func # in f # wrapper2 ,after func # wrapper1 ,after func
图解

从上图可以看到,从1-9步是装饰器的装载过程,10-18步是执行过程.结论:多个装饰器装饰同一个函数时,装载顺序是从下到上,但执行顺序却是从上到下,可以理解为创建了一个装饰器栈(先进后出)
python基础(8)-装饰器函数&进阶的更多相关文章
- 十. Python基础(10)--装饰器
十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...
- python基础之 装饰器,内置函数
1.闭包回顾 在学习装饰器之前,可以先复习一下什么是闭包? 在嵌套函数内部的函数可以使用外部变量(非全局变量)叫做闭包! def wrapper(): money =10 def inner(num) ...
- Day11 Python基础之装饰器(高级函数)(九)
在python中,装饰器.生成器和迭代器是特别重要的高级函数 https://www.cnblogs.com/yuanchenqi/articles/5830025.html 装饰器 1.如果说装 ...
- python基础--定义装饰器(内置装饰器)
装饰器的定义: 装饰器本质上就是一个python函数,它可以让其它函数在不需要做任何代码改动的前提下增加额外的功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景中,比如-- >插入 ...
- [python基础]关于装饰器
在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...
- 1.16 Python基础知识 - 装饰器初识
Python中的装饰器就是函数,作用就是包装其他函数,为他们起到修饰作用.在不修改源代码的情况下,为这些函数额外添加一些功能,像日志记录,性能测试等.一个函数可以使用多个装饰器,产生的结果与装饰器的位 ...
- python基础之装饰器(实例)
1.必备 #### 第一波 #### def foo(): print 'foo' foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print ...
- 【Python基础】装饰器的解释和用法
装饰器的用法比较简单,但是理解装饰器的原理还是比较复杂的,考虑到接下来的爬虫框架中很多用到装饰器的地方,我们先来讲解一下. 函数 我们定义了一个函数,没有什么具体操作,只是返回一个固定值 请注意一下缩 ...
- python之路——装饰器函数
阅读目录 楔子 装饰器的形成过程 开放封闭原则 谈装饰器主要功能和装饰器固定结构 带参数的装饰器 多个装饰器装饰一个函数 返回顶部 楔子 作为一个会写函数的python开发,我们从今天开始要去公司上班 ...
随机推荐
- Android中的指纹识别
转载请注明出处:http://blog.csdn.net/wl9739/article/details/52444671 评论中非常多朋友反映,依据我给出的方案,拿不到指纹信息这个问题,在这里统一说明 ...
- SQL Server In-Memory OLTP Internals for SQL Server 2016
SQL Server In-Memory OLTP Internals for SQL Server 2016 这份白皮书是在上一份<SQL Server In-Memory OLTP Inte ...
- C# 参数签名字符串按 ASCII码排序,注意其中的坑
参数签名中通常是按键值对中键名称的ASCII按从小到大的顺序排序后进行hash为签名字符串.不要直接使用 SortedDictionary<string, string> 有坑的,他是按数 ...
- application.properties详解 --springBoot配置文件【转载】
# spring boot application.properties配置的各个属性详解 # 该示例文件作为标准提供.(官方文档 翻译过来的) # 还是花了些功夫翻译,各位如果转发,请留下本文地址, ...
- DatagramSocket(邮递员):对应数据报的Socket概念,不需要创建两个socket,不可使用输入输出流。
UDP编程: DatagramSocket(邮递员):对应数据报的Socket概念,不需要创建两个socket,不可使用输入输出流. DatagramPacket(信件):数据包,是UDP下进行传输数 ...
- javascript:没有定义的变量和没有定义的属性
1. 没有定义的变量 window.onload = function() { alert(a); // 报错: Uncaught ReferenceError: a is not defined / ...
- linux命令中的字符串中间增加指令,例如路径中增加日期变量,实时获取当前的日期
`command` 倒引号 (backticks) 在前面的单双引号,括住的是字串,但如果该字串是一列命令列,会怎样?答案是不会执行.要处理这种情况,我们得用倒单引号来做.fdv=`date +%F` ...
- 【Static Program Analysis - Chapter 4】格理论(Lattice Theory)与程序分析
# 从一个例子说起, **任务:给定这样一段代码,假设我们想分析出这段代码中,每个数值型变量和表达式的符号,即正数,负数或0.** 此外,还有可能出现两种情况就是: 1.我们无法分析出结果,即我们无法 ...
- python2.7环境下的flask项目导入模块失败解决办法
如下一个flask项目的目录: 这个flask项目在python3.6环境下可以正常启动,但是在python2.7环境下如下报错提示: 提醒模块找不到.如下解决方法: 只需要在views目录里面加一个 ...
- Struts2与spingmvc区别
1.Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上Spr ...