【一】无参装饰器语法糖
-
没有语法糖的装饰器方法:
def timer(func):def inner():start = time.time()func()end = time.time()print(f"总耗时:{end - start} s") return inner def transform():time.sleep(2) tra = timer(transform) tra()
-
有语法糖的:
def timer(func):def inner():start = time.time()func()end = time.time()print(f"总耗时:{end - start} s") return inner @timer # 加一个@timer def transform():time.sleep(2) transform()
【二】有参装饰器的语法糖
-
有参装饰器
def timer(func):def inner(*args, **kwargs):start = time.time()func(*args, **kwargs)end = time.time()print(f"总耗时:{end - start} s") return inner @timer def transform(username, money):print(f'{username} | {money}')time.sleep(2) transform("knight",666)
-
有参语法糖(单个语法糖)
-
现在只能使用一种装饰器并且在装饰器中不能切换
login_dict = {'username': 'knight'} def login_auth(func):def inner(*args, **kwargs):if login_dict.get('username'):func(*args, **kwargs)else:print(f"请先登录") return inner def timer(func):def inner(*args, **kwargs):start = time.time()func(*args, **kwargs)end = time.time()print(f"总耗时:{end - start} s") return inner @login_auth def transform(username, money):print(f'{username} | {money}')time.sleep(2) transform("knight", 666)
-
多语法糖(这个方法依旧有点麻烦)
login_dict = {'username': 'knight'} def decr(tag):''' :param tag: 如果返回'login_auth' ---进入登录认证装饰器:return: 否则返回 计时装饰器'''if tag == 'login_auth':def login_auth(func):def inner(*args, **kwargs):if login_dict.get('username'):func(*args, **kwargs)else:print(f"请先登录") return inner return login_authelif tag == 'timer':def timer(func):def inner(*args, **kwargs):start = time.time()func(*args, **kwargs)end = time.time()print(f"总耗时:{end - start} s") return inner return timer def transform(username, money):print(f'{username} | {money}')time.sleep(2) transform = decr(tag='timer')(transform) transform('knight', 666) print(transform)
-
多语法糖优化
login_dict = {'username': 'knight'} def decr(tag):''' :param tag: 如果返回'login_auth' ---进入登录认证装饰器:return: 否则返回 计时装饰器'''if tag == 'login_auth':def login_auth(func):def inner(*args, **kwargs):if login_dict.get('username'):func(*args, **kwargs)else:print(f"请先登录")return innerreturn login_authelif tag == 'timer':def timer(func):def inner(*args, **kwargs):start = time.time()func(*args, **kwargs)end = time.time()print(f"总耗时:{end - start} s") return inner return timer @decr(tag='login_auth') def transform(username, money):print(f'{username} | {money}')time.sleep(2) transform('knight', 666)
语法糖案例
def dec_a(func):# 【二】调用 dec_a 函数触发print('111') def wrapper(*args, **kw):# 【三】执行 main_func()print('222')func(*args, **kw) # b_wrapper(main_func)# 【七】结束上面的 b_wrapper 回来print('333') return wrapper def dec_b(func):# 【一】进来 dec_b 函数print('aaa') def wrapper(*args, **kw):# 【四】因为在 dec_a 的 wrapper 里面调用了 func --> 就是我自己print('bbb')func(*args, **kw) # main_func# 【六】执行完 main_func 又回来继续走print('ccc') return wrapper @dec_a @dec_b # 多层语法糖的时候谁在下先调用谁,但是执行校验的时候是谁在上先校验谁 def main_func():# 【五】回到真正的 main_funcprint('main_func') ''' # 定义顺序是一个个挨着定义 # 调用顺序是倒着谁在下先调用谁 main_func = dec_b(main_func) # main_func = b_wrapper (main_func) main_func = dec_a(main_func) # main_func = a_wrapper (b_wrapper(main_func)) main_func() # a_wrapper # aaa # 111 # 222 # bbb # main_func # ccc # 333 ''' main_func() # 指定结果打印顺序
【练习】
方法一:
# 定义一个数据字典存储用户数据 user_dict = {'username': 'knight', 'password': '123'} # 分别校验用户名和密码 # 分别是两个装饰器 # 一个负责校验用户名是否存在 def check_username(func):def inner(*args, **kwargs):username_input = input("用户名:").strip()userdict_ = user_dict.get('username_input')if not userdict_ == username_input:print(f"当前用户{username_input}未注册")else:func(*args, **kwargs) return inner # 一个负责校验密码是否正确 def check_password(func):def inner(*args, **kwargs):password_input = input("密码:").strip()passworddict_ = user_dict.get('password_input')if passworddict_ != password_input:print(f'密码错误')else:func(*args, **kwargs) return inner # 只有符合上一个装饰器的条件才能走到下一个装饰器 def transform(username, money):print(f"{username} 转账 {money}") transform(username='knight', money=6666)
方法二:语法糖
user_dict = {'username': 'knight', 'password': '123'}def check_user(tag):if tag == 'username':def check_username(func):def inner(*args, **kwargs):username_input = input(f'用户名').strip()username_dict = user_dict.get(username_input)if not username_dict != username_input:print(f"当前用户{username_input}不允许使用")else:func(*args, **kwargs)return innerreturn check_usernameelif tag == 'password':def check_password(func):def inner(*args, **kwargs):password_input = input(f'密码').strip()password_dict = user_dict.get("password")if password_dict != password_input:print(f'密码错误')else:func(*args, **kwargs)return innerreturn check_password@check_user(tag='username') @check_user(tag='password') def transform(username, money):print(f"{username} 转账 {money}")transform(username='knight', money=6666)
【三】装饰器的修复技术
import time# 我们可以通过help函数查看函数内部的注释def timer(func):''':param func: 传入的参数:return:'''def inner(*args, **kwargs):''':param args: 可变长位置参数:param kwargs: 可变长关键字参数:return:'''start = time.time()func(*args, **kwargs)end = time.time()print(end - start)return inner@timer def run():print(f"run 开始")time.sleep(2)print(f"run 结束")print(help(run)) # 装饰器其实就是在不改变源代码调用方式的基础上额外增加新功能 # 别人就可能通过help查看内部的注释 ---> 把用户名和密码都加进去了
装饰器修复技术
from functools import wrapsdef timer(func):''':param func: 传入的参数:return:'''@wraps(func)def inner(*args, **kwargs):''':param args: 可变长位置参数:param kwargs: 可变长关键字参数:return:'''start = time.time()func(*args, **kwargs)end = time.time()print(end - start)return inner@timer def run():print(f"run 开始")time.sleep(2)print(f"run 结束")print('下面包好的',help(run))