装饰器
一、装饰器
装饰器是由名称空间,函数对象,闭包函数组合而来的
器:指的就是以一种工具
装饰:给被装饰物添加额外的功能
装饰器的原则
装饰器遵守开放封闭原则
开放:对扩展开放
封闭:对修改封闭
装饰器的核心思想
在不改变对被装饰对象内部原有的代码和原有调用方式的基础上添加额外的功能
二、装饰器的简易版本
假如我们要给一个函数添加一个统计执行时间的功能
import time
def index():
time.sleep(3)
print('hello')
def funcion():
time.sleep(1)
print('hi')
# 该方法就可以看成是一个简易的装饰器
def outer(fucn):
def get_time():
strat_time = time.time()
fucn()
end_time = time.time()
print('程序所执行的时间为%s'%(end_time-strat_time))
return get_time
index = outer(index)
index()
funcion = outer(funcion)
funcion()

三、解决参数问题
在使用装饰器时,原本函数带有参数时,上面的简易装饰器会报错会需要传入参数,这时候为了解决这个问题可以应用以下的方法
import time
def outer(fucn):
def get_time(*args, **kwargs): # 接受原有函数的参数并组织成元组的形式
strat_time = time.time()
fucn(*args,**kwargs) # 将元组内的元素打散并变成位置参数或者关键字参数的形式传入
end_time = time.time()
print('程序所执行的时间为%s' % (end_time - strat_time))
return get_time
def index(name):
time.sleep(1)
print('%s'%name)
index = outer(index)
index('jason')

四、解决返回值问题
在装饰器中,我们如果想要将装饰器的返回值和原函数的返回值一致,我们就需要在装饰器中将函数原来的返回值返回
import time
def outer(fucn):
def get_time(*args, **kwargs):
strat_time = time.time()
res = fucn(*args, **kwargs) #使原函数的值赋值给res
end_time = time.time()
print('程序所执行的时间为%s' % (end_time - strat_time))
return res #返回原函数的值
return get_time
def index():
time.sleep(1)
print('from index')
return 'from index' #原函数的值
index = outer(index)
print(index()) #查看是否与原来的值相等

五、认证装饰器
如果想要在使用函数前用一个认证器来检验是否能用使用函数,我们可以用到一个认证装饰器
# 简单版本
import time def index(): time.sleep(3) print('hello') def resgiser(): time.sleep(1) print('注册功能') def login_auth(fucn): def auth(*args, **kwargs): name = input('请输入您的用户名>>>: ') pwd = input('请输入您的密码>>>: ') if name == 'king' and pwd =='123': res = fucn(*args, **kwargs) return res else: print('用户名密码错误,无法执行函数') return auth
index = login_auth(index) index()
# 高级版本
import time is_login_dic = {'is_login': False} #定义一个全局的字典用于判断用户是否登录过 def index(): time.sleep(3) print('hello') def resgiser(): time.sleep(1) print('注册功能') def login_auth(fucn): def auth(*args, **kwargs): if is_login_dic.get('is_login'): #如果用户没登陆过则不执行,登陆过则执行下面的功能 res = fucn(*args,**kwargs) return res name = input('请输入您的用户名>>>: ') pwd = input('请输入您的密码>>>: ') if name == 'king' and pwd =='123': res = fucn(*args, **kwargs) is_login_dic['is_login'] = True #用户登录过后将Flase改成True return res else: print('用户名密码错误,无法执行函数') return auth index = login_auth(index) index() resgiser = login_auth(resgiser) resgiser()
六、装饰器固定模板
def outer(fucn):
def inner(*args, **kwargs):
print('执行函数之前可以添加的模板')
res = inner(*args, **kwargs) #执行被装饰的函数
print('执行函数之后可以添加的模板')
return res #将被装饰的函数的值返回
return inner
七、装饰器语法糖
装饰器语法糖就是一种可以让我们的函数在使用装饰器时可以变得更加简洁的一种方式
def outer(fucn):
def inner(*args, **kwargs):
print('执行函数之前可以添加的模板')
res = inner(*args, **kwargs)
print('执行函数之后可以添加的模板')
return res
return inner
@outer # 语法糖 等于省略了 index = outer(index)
def index():
print('hello')
@outer # 语法糖 等于省略了 shopping = outer(shopping)
def shopping():
print('购物功能')
语法书写规范:
语法糖必须紧贴被装饰对象的上方
语法糖内部调用原理:
会自动将下面紧贴的被装饰对象的名字当作参数传给装饰器函数用
八、双层语法糖
import time
def get_time(func):
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs) # 执行被装饰的函数
end_time = time.time()
print('函数执行时间:%s'%(end_time-start_time))
return res # 将被装饰函数执行之后的返回值返回
return inner
# 校验用户登录装饰
def login_auth(func):
def inner(*args, **kwargs):
# 1.先获取用户的用户名和密码
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 2.校验用户名和密码是否正确
if username == 'jason' and password == '123':
res = func(*args, **kwargs) # 执行被装饰的函数
return res # 将被装饰函数执行之后的返回值返回
print('用户名或密码错误 无权限执行')
return inner
@login_auth
@get_time
def index():
time.sleep(1)
print('from index')
index()
执行的顺序

九、装饰器的修复
修复技术就是为了让被装饰对象更加不容易被察觉被装饰了,有一个固定的代码
from functools import wraps #固定的修复代码
def outer(func):
@wraps(func) #固定的修复代码
def inner(*args, **kwargs):
print('执行函数之前可以添加的额外功能')
res = func(*args, **kwargs)
print('执行函数之后可以添加的额外功能')
return res
return inner

十、有参装饰器
我们还可以给装饰器增加一个参数
def outer(source_data):
# source_data = 'file'
def login_auth(func):
def auth(*args,**kwargs):
# 2.校验用户名和密码是否正确
# 数据的校验方式可以切换多种
if source_data == 'file':
# 从文件中获取用户数据并比对
print('file文件获取')
elif source_data == 'MySQL':
# 从MySQL数据库中获取数据比对
print('MySQL数据库获取')
elif source_data == 'postgreSQL':
# 从postgreSQL数据库中获取数据对比
print('postgreSQL数据库获取')
else:
print('用户名或密码错误 无法执行函数')
return auth
return login_auth
@outer('file') # 使用参数'file' 来从文件中获取数据
def index():
print('from index')
@outer('MySQL') # 使用参数'MySQL'来从MySQL中获取数据
def home():
print('from home')
index()
home()


浙公网安备 33010602011771号