1、装饰器
1.1、什么是装饰器
器指的是工具/功能
装饰指的是为被装饰对象添加额外的功能
大白话:定义装饰器就是定义了一个函数,该函数就是用来为其他函数添加额外的功能的
1.2、为何要用装饰器
程序的开发需要遵循一个原则:开放封闭原则
开放:指的是对拓展功能开放
封闭:指的是对修改源代码封闭
总结:装饰器就是在不修改被装饰对象源代码以及调用方式的前提为被装饰对象添加上新功能
1.3、如何使用装饰器
1.3.1、模拟统计程序的运行时间
import time
def index(x, y):
time.sleep(3)
print('index===>', x, y)
def home(name):
time.sleep(2)
print('home====>', name)
def outter():
x = index
def wrapper(a, b):
start_time = time.time()
x(a, b)
stop_time = time.time()
print("run time is :%s" % (stop_time - start_time))
return wrapper
index = outter()
index(1, 2)
1.3.2、装饰器的改进1
import time
def index(x, y):
time.sleep(3)
print('index===>', x, y)
def home(name):
time.sleep(2)
print('home====>', name)
def outter(x):
def wrapper(*args,**kargs):
start_time = time.time()
x(*args,**kargs)
stop_time = time.time()
print("run time is :%s" % (stop_time - start_time))
return wrapper
index = outter(index)
home = outter(home)
index(1, 2)
home("allen")
1.3.3、装饰器的改进2
import time
def index(x, y):
time.sleep(3)
print('index===>', x, y)
return 456
def home(name):
time.sleep(2)
print('home====>', name)
return 123
def outter(x):
def wrapper(*args, **kargs):
start_time = time.time()
res = x(*args, **kargs)
stop_time = time.time()
print("run time is :%s" % (stop_time - start_time))
return res
return wrapper
index = outter(index)
home = outter(home)
res1 = index(1, 2)
res2 = home("allen")
print("====>",res1)
print("====>",res2)
1.4、语法糖
import time
def outter(x):
def wrapper(*args, **kargs):
start_time = time.time()
res = x(*args, **kargs)
stop_time = time.time()
print("run time is :%s" % (stop_time - start_time))
return res
return wrapper
@outter
def index(x, y):
time.sleep(3)
print('index===>', x, y)
return 456
@outter
def home(name):
time.sleep(2)
print('home====>', name)
return 123
res1 = index(1, 2)
res2 = home("allen")
print("====>", res1)
print("====>", res2)
1.5、wraps的使用
from functools import wraps
def timmer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start=time.time()
res = func(*args, **kwargs)
stop=time.time()
print(stop - start)
return res
return wrapper
@timmer
def index(x, y):
"""
这是index函数的文档注释
"""
time.sleep(1)
print('index===>', x, y)
return 456
help(index)
1.6、完整的装饰器模板总结
from functools import wraps
def outter(func):
@wraps(func)
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
1.7、叠加多个装饰器的加载、运行分析
def deco1(func1):
def wrapper1(*args, **kwargs):
print('正在运行===>deco1.wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def deco2(func2):
def wrapper2(*args, **kwargs):
print('正在运行===>deco2.wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def deco3(x):
def outter3(func3):
def wrapper3(*args, **kwargs):
print('正在运行===>deco3.outter3.wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
return outter3
@deco1
@deco2
@deco3(111)
def index(x, y):
print('from index %s:%s' % (x, y))
index(1, 2)
结论:
1、装饰器的加载顺序是自下而上的
2、装饰器的执行顺序是自上而下的
2、有参装饰器
2.1、定义与使用
由于语法糖@的限制,outter函数只能有一个参数,并且该参数只用来接收被装饰对象的内存地址
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
@outter
def index(x,y):
print(x,y)
引出两点:
1、可以通过闭包的方式为函数体传参,可以包一层,也可以包两层
2、@后跟的必须是一个函数的内存地址
@函数的内存地址(1,2) 是可以的,但是前提是调用函数"函数的内存地址(1,2)"的
返回值必须是一个函数的内存地址
2.2、有参装饰器的应用
def outter2(mode):
def outter(func):
def wrapper(*args, **kwargs):
inp_name=input("please input your name: ").strip()
inp_pwd=input("please input your password: ").strip()
if mode == "file":
print('认证来源=====>file')
with open('user.db', mode='rt', encoding='utf-8') as f:
for line in f:
name_db,pwd_db=line.strip('\n').split(':')
if inp_name == name_db and inp_pwd == pwd_db:
print('login successful')
res = func(*args, **kwargs)
return res
else:
print("账号或密码错误")
elif mode == "ldap":
print('认证来源=====>ldap')
elif mode == "mysql":
print('认证来源=====>mysql')
else:
print("未知的认证来源")
return wrapper
return outter
@outter2(mode="mysql")
def index(x, y):
print('index===>', x, y)
index(1, 2)
2.3、有参装饰器模板总结
def 有参装饰器(x,y,z):
def outter(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
return outter
@有参装饰器(1,y=2,z=3)
def 被装饰对象():
pass