一、双层语法糖
'''双层语法糖'''
import time
'''验证装饰器'''
def login(xxx):
def count(*args,**kwargs):
'''装饰对象被调用前,添加的新功能'''
username = input('请输入用户名>>>:').strip()
password = input('请输入密码>>>:').strip()
if username == 'chen' and password == '123':
rel = xxx(*args,**kwargs)
'''装饰对象被调用后,添加的新功能'''
return rel
else:
print('请输入正确的账号或密码')
return count
'''计算执行时间装饰器'''
def outer(zzz):
def get_time(*args,**kwargs):
'''被装饰对象调用前,添加的新功能'''
start_time = time.time()
res = zzz(*args,**kwargs)
'''被装饰对象调用后,添加的新功能'''
end_time = time.time()
print('执行函数所消耗的时间>>>>:%s' % (end_time - start_time))
return res
return get_time
@login
@outer
def show():
time.sleep(2)
print('I AM KING')
show()
'''
双层语法糖内部运行步骤:
1.先运行装饰器outer
2.因为有语法糖所以函数show会直接被装饰器outer当成它的形参
3.因没有函数体代码,故直接运行返回值,它的返回值是它的第二层函数的函数名
4:所以就得到了get_time=outer(show)(这里为什么是get_time,是因为不是最后一层,
所以不能直接用show来)
5.继续运行第二个装饰器login
6.因为有语法糖所有上层函数的函数名(get_time)会被直接当成装饰器login的形参
7.因没有函数体代码,故直接运行返回值,它的返回值也是它的第二层函数的函数名
8.所以就得到了show=login(get_time)>>>>>>count,
(因为这里是最后一层装饰器所以可以直接用show来等于)
9.调用show(),因为show在步骤7那里拿到的是count,所有show()======count()
10.所有运行装饰器login内层函数count,运行它的函数体代码,得到了一个rel=xxx()的值,
而xxx就是装饰器第一层函数的形参get_time,所以就是rel=get_time()
11.count函数运行返回值,返回值是rel就是get_time(),所有运行装饰器outer的内层函数
12.运行get_time函数中的函数体代码,而后得到了res=zzz(),
而这个zzz就是第一层装饰器的形参show,故就是res=show()
13.继续运行函数体代码后,执行返回值,返回res,而res就是show(),
故执行调用真正的show函数
14.最后运行函数show的函数体代码
'''
二、三层语法糖(多层)
'''与双层语法糖的内部运行是一样的,故这里就不详细写步骤了'''
def outter1(func1):
print('加载了outter1')
def wrapper1(*args,**kwargs):
print('执行了wrapper1')
res1=func1(*args,**kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args,**kwargs):
print('执行了wrapper2')
res2=func2(*args,**kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args,**kwargs):
print('执行了wrapper3')
res3=func3(*args,**kwargs)
return res3
return wrapper3
@outter1
@outter2
@outter3
def index():
print('hello world')
index()
'''
判断以上三层语法糖及函数index的打印顺序
最终得到的顺序结果为:
1.加载了outter3 2.加载了outter2
3.加载了outter1 4.执行了wrapper1
5.执行了wrapper2 6.执行了wrapper3
7.hello world
'''
三、装饰器的修复技术(了解)
import time
from functools import wraps
'''装饰器的修复技术'''
def outer(xxx):
@wraps(xxx)
def inner(*args,**kwargs):
start_time = time.time()
rel=xxx(*args,**kwargs)
end_time = time.time()
print('执行所消耗的时间>>>>:%s' % (end_time - start_time))
return rel
return inner
@outer
def index():
print('hello world')
'这个是没加装饰器运行打印的结果'得到的是index的内存地址
print(index)
'这个是加装饰器没加修复技术运行打印的结果'得到的是伪装的内存地址
print(index)
'这个是既加了装饰器又加了修复技术运行打印的结果'得到的是index的内存地址
print(index)
'''修复技术就是为了让装饰器伪装的更好'''
四、有参装饰器
'''有参装饰器'''
def outter(type):
def login_auth(xxx):
def auth(*args,**kwargs):
'''
校验用户数据 数据的来源可以有很多 比如全局字典
全局列表 文本文件 数据库
数据的来源不同 处理方式就不同 对应的代码编写就不一样
分支结构处理 然后根据不同的参数提示 匹配不同的流程
根据不同的参数用户名和密码来自不同的位置
1. 文件中获取用户名和密码
2. 从MySQL中获取用户名和密码
3. 从oracle中获取用户名和密码
'''
if type == '1':
print('用户名和密码来自文件')
elif type == '2':
print('用户名和密码来自MySQL')
elif type == '3':
print('用户名和密码来自Oracle')
rel = xxx(*args,**kwargs)
return rel
return auth
return login_auth
@outter(1)
def home():
pass
home()
@outter(2)
def index():
pass
index()
@outter(3)
def func():
pass
func()
'''
函数名加括号 执行优先级最高
@outter('3')
左侧是语法糖结构 右侧是函数名加括号结构
先执行函数调用 outter('3') 返回值是login_auth
在执行语法糖结构 @login_auth
发现最后还是一个普通的装饰器
有参装饰器目的仅仅是给装饰器传递额外的参数
装饰器最多的就三层嵌套
并且三层嵌套的结构使用频率不高(最多是使用别人写好的有参装饰器)
from functools import wraps
@wrps(xxx)
'''