python装饰器
python装饰器--开放封闭原则
知识点回顾
# *args **kwargs
def wrapper(*args,**kwargs): # 接受(形参) args=(1,2,3) kwargs={'a':1,'b':2}
index(*args,**kwargs) # 打散(实参)
# index(*(1,2,3),**{'a':1,'b':2})
# index(1,2,3,a=1,b=2) 原封不动的传给index
wrapper(1,2,3,a=1,b=2)
1 ----> 5装饰器无参
6 ----> 7装饰器有参
1. 原函数无参的装饰
在不改变原代码上,添加新的功能
装饰器需要定义在原函数前面,并且命名要明确
import time
'''装饰函数'''
def timmer(func): # 1.传入函数名
def wrapper():
start = time.time()
func() # 2.执行传入函数
end = time.time()
print(end - start)
return wrapper # 3.返回了函数名
'''原来代码'''
def index():
time.sleep(3)
print('index无参数')
'''index旧瓶新装'''
index = timmer(index) # 4.等于把旧index传入到wrapper函数中了
# 4-1 新的index = warpper内存地址
index() # 5.新的index,其实调用-->wrapper()
1.1 语法糖
语法糖:让你开心的事
import time
def timmer(func):
def wrapper():
start = time.time()
func()
end = time.time()
print(end - start)
return wrapper
@timmer # 1.语法糖其实是封装了上面[4]的写法,使其更加直观->@装饰器名
def index():
time.sleep(3)
print('index无参数')
index() # 2.新的index,其实调用-->wrapper()
2. 原函数有参的装饰器
import time
def timmer(func):
def wrapper(*args, **kwargs): # 1.传入不确定参数
start = time.time()
func(*args, **kwargs) # 2.把参数传给原函数(⚠️一定要带 * 号)
end = time.time()
print(end - start)
return wrapper
@timmer
def index(x, y):
time.sleep(3)
print('index %d %d' % (x, y))
index(1, 2)
index 1 2
3.014557123184204
3.原函数有返回值的装饰器
import time
def timmer(func):
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs) # 2.res接受原函数返回值
end = time.time()
print(end - start)
return res # 3.在装饰器末尾加上return res
return wrapper
@timmer
def index(x, y):
time.sleep(3)
return x + y # 1.原函数有返回值
res = index(1, 2) # 4.通过装饰器后拿到了返回值
4.原函数执行多个装饰器执行
多个装饰器是从底下向上运行的
def wrapper1(func):
def inner1(*args, **kwargs):
print("wrapper1 装饰函数前 可以做一些事 ")
ret = func(*args, **kwargs)
print("wrapper1 装饰函数后 可以做一些事 ")
return ret
return inner1
def wrapper2(func):
def inner2(*args, **kwargs):
print("wrapper2 装饰函数前 可以做一些事 ")
ret = func(*args, **kwargs)
print("wrapper2 装饰函数前 可以做一些事 ")
return ret
return inner2
@wrapper2 # 2.
@wrapper1 # 1.
def func():
print("我是函数,我被两个装饰器装饰")
return "函数 返回值"
ret = func()
print(ret)
# ----------------------------运行结果------------------------
# wrapper2 装饰函数前 可以做一些事
# wrapper1 装饰函数前 可以做一些事
# 我是函数,我被两个装饰器装饰
# wrapper1 装饰函数后 可以做一些事
# wrapper2 装饰函数前 可以做一些事
# 函数 返回值
5.伪装的更像原函数
def timmer(func):
def wrapper(*args,**kwargs)
res =func(*args,**kwargs)
return res
wrapper.__name__ = func.__name__ # 3.需要把原函数的内置属性赋值过来
wrapper.__doc__ = func.__doc__ # 4.不可能一个个的写完
......
retrun wrapper
@timmer
def index(x,y):
'''这是一个文档'''
print(x,y)
print(index.__name__) ---->index # 1.伪装原函数
print(index.__doc__)---->这是一个文档
5-1. from functools import wraps
⚠️⚠️⚠️一定要记住:wraps(func)
from functools import wraps # 1.wrpas(func)就是装饰器
def timmer(func):
@wraps(func) # 2.就是将原函数的内置属性拿过来
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
@timmer
def index(x, y):
'''这是一个文档'''
print(x, y)
print(index.__name__)
print(index.__doc__)
index
这是一个文档
6.了解装饰器@作用---为7做铺垫
@名字 --> home = 名字(home)
def home():
pass
@名字()--> 先执行名字(),返回值---> home = 返回值(home)
def home():
pass
7.有参的装饰器(需要掌握)
- 装饰器其实用的wrapper函数
- 因为deco和wrapper中不能传入参数了
- 所有外面在套一层auth
from functools import wraps
def auth(a_type): # 1.外层在包一层函数,接受参数
def deco(func):
@wraps(func)
def wrapper(*args, **kwargs):
if a_type == 'XXX1': # 2,接受的参数来判断运行那个代码
print('XXX1')
res = func(*args, **kwargs)
return res
elif a_type == 'XXX2':
print('XXX2')
res = func(*args, **kwargs)
return res
elif a_type == 'XXX3':
print('XXX3')
res = func(*args, **kwargs)
return res
else:
print('a_type类型错误')
return wrapper
return deco # 3.返回函数deco
@auth('XXX1') # 4.使用语法糖添加类型【可变的】
def index1(x, y):
print(x + y)
@auth('XXX2') # 5.@名字()--> 先执行名字(),返回值deco-->[因为【3】return deoc]
def index2(x, y):
print(x + y)
@auth('XXX3') # 6.返回值已经是deco,再执行@deco,此时参数已经被传入内部了
def index3(x, y):
print(x + y)
if __name__ == '__main__':
index1(1, 2)
XXX1
3