装饰器的形成过程
通过学习和研究对python的装饰器有了一定的了解,为了加深印象,重新整理一遍,以下是个人的理解,并不是很全,后续有新的理解在进行修改或更新。
import time
def func1():
time.sleep(0.01)
print("this is func1")
def timer(fn):
def inner():
start = time.time()
fn()
end = time.time()
total = end - start
print(total)
return inner
func1 = timer(func1) //此时func1接收到的是inner
func1()
麻雀虽小,五脏俱全,装饰器的简单模型还是出来了,下面就是进行深一步的理解以及应用,通过一句语法糖来对装饰器进行简化
import time
def timer(fn):
def inner():
start = time.time()
fn()
end = time.time()
total = end - start
print(total)
return inner
@timer
def func1():
time.sleep(0.01)
print("this is func1")
// func1 = timer(func1) #此时这一行代码就被@timer所替代
func1()
到这里,简单的总结下:
装饰器的本质:一个闭包函数
装饰器的功能:在不改变原函数以及其调用方式的情况下对原函数的功能进行扩展.
以上装饰器是装饰不带参数的函数,那么下面就是要介绍带参数的函数
import time
def timer(fn):
def inner(param):
start = time.time()
fn(param)
end = time.time()
total = end - start
print(total)
return inner
@timer
def func1(param):
time.sleep(0.01)
print(param)
// func1 = timer(func1)
func1("我就是带参数的函数")
其实装饰带参数的函数并不是什么难事,但是如果要带两个参数或者是更多参数,那么要如何进行传递呢
import time
def timer(fn):
def inner(*args,**kwargs):
start = time.time()
fn(*args,**kwargs)
end = time.time()
total = end - start
print(total)
return inner
@timer
def func1(param):
time.sleep(0.01)
print("get the param : %s" %param)
@timer
def func2(param1,param2):
time.sleep(0.01)
print("get the param param1 :"+param1 + ", param2 :" + param2)
func1("我就是带参数的函数")
func2("我就是带参数的函数1","我就是带参数的函数2")
这就是解决传递多个参数的问题
*args:(表示的就是将实参中按照位置传值,多出来的值都给args,且以元祖的方式呈现)
**kwargs:(表示的就是形参中按照关键字传值把多余的传值以字典的方式呈现)
现在参数传递的问题已经解决了,但是如果你的函数有返回值呢
import time
def timer(fn):
def inner(*args,**kwargs):
start = time.time()
ret = fn(*args,**kwargs)
end = time.time()
total = end - start
print(total)
return ret
return inner
@timer
def func1(param):
time.sleep(0.01)
print("get the param : %s" %param)
return "return the value"
// func1 = timer(func1)
func1("我就是带参数的函数")
print(func1("我就是带参数的函数"))
到这里装饰器已经基本上是介绍完了,完美的,但是正常情况下我们查看函数的一些信息时常常会出现失败的情况
def index():
'''这里是注释信息'''
print("the message from index")
print(index.__name__) //这里获取的是调取的方法名
print(index.__doc__) //这里获取的是注释信息
为了不出现失效的情况,在装饰器上加一点来对他进行完善
from functools import wraps
def doc(fn):
@wraps(fn) //要加载内层函数上
def wrapper(*args,**kwargs):
return fn(*args,**kwargs)
return wrapper
@doc
def index():
'''这里是注释信息'''
print("the message from index")
print(index.__name__)
print(index.__doc__)
到这里装饰器已经介绍完毕
开放封闭原则
- 对扩展是开放的
任何一个程序,不可能在设计之初就已经想好了所有的功能以及后续不会有添加和修改,所以我们允许对代码进行修改和添加 - 对修改是封闭的
为什么是要对修改是封闭的呢?我们可以想想,我们写一个函数,我们把函数交付被别人进行使用,如果我们在对其进行修改的话,就很可能会影响已经在使用该函数的用户
装饰器完美的遵循了这个开放封闭原则
装饰器的主要功能和装饰器的固定结构
- 装饰器的主要功能:
在不改变函数调用的方式的基础上再函数的前面或者是后面添加功能 - 装饰器的固定结构
def timer(func):
def inner(*args,**kwargs):
'''执行函数之前要做的'''
re = func(*args,**kwargs)
'''执行函数之后要做的'''
return re
return inner
from functools import wraps
def deco(func):
@wraps(func) //加在最内层函数正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper
- 带参数的装饰器
假如你有成千上万个装饰器,现在你要把这些装饰器全部取消掉,你会怎么做
def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''执行函数之前要做的''')
re = func(*args,**kwargs)
if flag:
print('''执行函数之后要做的''')
return re
return inner
return timer
@outer(False)
def func():
print(111)
func()
- 多个装饰器装饰同一个函数
有时候我们也会用多个装饰器来装饰同一个函数
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
@wrapper2 // f = wrapper2(f) --> wrapper2(inner1) == inner2
@wrapper1 // f = wrapper1(f) == inner1
def f():
print('in f')
f() // --> inner2()
//执行结果为
/**
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
*/