一.初识
1.引入
现在有这样两个函数
def func1():
print("这是func1")
def func2():
print("这是func2")
我想让他俩每次执行之前先打印一下时间,就是这样
import time
def func1():
print("这是func1")
def func2():
print("这是func2")
print(time.time())
func1()
print(time.time())
func1()
但是,如果我有很多函数之前都要打印时间,一个一个写太麻烦,所以我们把打印时间这段代码封装成函数
import time
def timer():
print(time.time)
def func1():
timer()
print("这是func1")
def func2():
timer()
print("这是func2")
问题又来了,我不想动我原来的代码,而且我也不想改变我调用函数的方式,我就是想给他加这个打印时间的功能。我们考虑可以用闭包搞一下
import time
def timer(func):
def inner():
print(timer)
func()
return inner
def func1():
print("这是func1")
def func2():
print("这是func2")
#使用:
func1 = timer(func1)
func1() #这样搞的话,表面上看起来原函数代码没变,而且调用方式也没变
其实,不知不觉我们已经把装饰器给整出来了。
装饰器的作用就是:不改变原来函数的代码和调用方式,额外增加新的功能
实质上是闭包的一种应用
一个基本的装饰器写法及使用:
def wrapper(func):
def inner(*args,**kwargs):
...... #执行函数前的操作
ret = func()
return ret
return inner #执行函数后的操作
@wrapper #@wrapper是py的语法糖,下面再说
def func1():
pass
2.理解
(1)理解装饰器不会改变原函数的代码和调用方式?
(2)为啥是@wrapper
首先了解一下语法糖是什么?
语法糖:计算机语言添加的某种语法,对计算机语言的功能没有任何影响,但是更方便程序员的使用
@wrapper是py的语法糖,py开发者规定装饰器就是这样使用的.我们只要记住这个用法就好了,但是要了解@wrapper的工作流程:
(3)传参问题
def wrapper(func):
def inner():
func(num)
return inner
@wrapper
def func1(num):
return "num"
print(func1(5))
运行结果是这样:
为什么会这样?因为上述代码根本没把参数传进去
上边已经分析过了,执行func1(1)—>inner(1),但是inner本身就没定义参数,硬传肯定会报错
(4)返回值问题
看一段代码
def wrapper(func):
def inner(num):
func(num)
return inner
@wrapper
def func1(num):
return "num"
print(func1(5))
运行结果:
这个问题也很常见,为什么会是None?因为我们没有接收返回值,我们接收原func1函数的返回值,就得去原func1函数执行的地方拿,也就是inner函数里。
二.进阶
1.装饰器的修复技术
def wrapper1(func):
def inner():
print("前")
ret = func()
print("后")
return ret
return inner
@wrapper1
def func1():
print("这是func1")
print(func1.__name__)
结果是:inner,加了装饰器的话,原函数的名称和文档都会变,这样肯定不行,我还是想要原函数自己的东西,这就得用装饰器的修复技术
from functools import wraps
def wrapper2(func):
@wraps(func)
def inner():
print("前")
ret = func()
print("后")
return ret
return inner
@wrapper2
def func2():
pritn("这是func2")
print(func2.__name__) #结果为func2
2.多个装饰同一个函数
def wrapper1(func):
def inner():
print("wrapper1前")
func()
print("warpper1后")
return inner
def wrapper2(func):
def inner():
print("wrapper2前")
func()
print("wrapper2后")
return inner
@wrapper2
@wrapper1
def func1():
print("func")
func1()
运行结果:
wrapper2前
wrapper1前
func
warpper1后
wrapper2后
其实也不难,慢慢捋一捋