装饰器
装饰器 decorator
1. 功能
-
引入日志
-
函数执行时间统计
-
执行函数前预备处理
-
执行函数后清理功能
-
权限校验等场景
-
缓存
2. 原则
定义函数遵循 闭包
的原则,函数
作为 参数
def dec_func(f): # 装饰器函数:闭包+函数作为参数
def check():
f()
return check
# 使用装饰器函数
# 1.调用dec_func函数 2.执行函数体中内容 3.加载内层函数
# 4.返回内层函数 5.将返回的内层函数给func赋值 (func = check)
@dec_func
def func (): # 功能函数
print('hello')
如果被装饰的 功能函数有返回值
,那么 装饰器函数
也一定要 有返回值
user_list = {'zhangsan': 'z0001', 'lisi': 'l0001', '1': '1'}
def login():
user_name = input('请输入用户名:')
password = input('请输入密码:')
r = check_login(user_name, password)
return r
@dec_login
def check_login(user_name, password): # 被装饰的功能函数有返回值
if user_name in user_list:
if user_list[user_name] == password:
return True # 用户名与密码均正确,返回True
else:
return False # 用户名正确但密码错误,返回False
else:
return False # 用户名错误,返回False
pass
def dec_login(func):
def wrapper(*args, **kwargs):
print('登录验证中')
r = func(*args,**kwargs) # 接收原函数的返回值
if r:
print('r is true') # 返回值是True,打印 'r is true'
return True # 返回True
else:
print('r is false') # 返回值是False,打印'r is false'
return False # 返回False
return wrapper
res = login()
print(res)
3. 实质
函数间调用:在内层函数里调用外部的功能函数
函数名的互相赋值:对于使用者来说调用的还是原来的功能函数,实质上在底层执行的是装饰器的内层函数。
4. 装饰器带参数
def 装饰器名(装饰器参数):
# 使用装饰器参数
def second(func):
def third(函数参数):
res = func(函数参数)
return res
return third
# 使用装饰器参数
return second
def dec_func(a,b): # 定义装饰器
print(a,b) # 使用装饰器参数
def dec_second(func):
def dec_third(a,b):
res = func(a,b)
res += 1
return res
return dec_third
return dec_second
@dec_func(1,2) # 装饰,并给出装饰器参数
def func(a,b):
return a+b
print(func(1,2))
==========================
1 2
4
5. 多层装饰器
谁离原函数最近先执行哪个装饰器,将第一层装饰器的返回结果传给第二层装饰器
最终原函数得到的地址是第二层装饰器的返回值wrapper的地址
def dec1(func):
def wrapper(*args,**kwargs):
func(*args,**kwargs)
print('装饰器1')
pass
return warpper
def dec2(func):
def wrapper(*args,**kwargs):
func(*args,**kwargs)
print('装饰器2')
pass
return wrapper
@dec2 # 后执行的装饰器
@dec1 # 先执行的装饰器
def func1():
print('功能函数')
return
func1()
====================
功能函数
装饰器1
装饰器2
6. 类装饰器
定义一个类作为装饰器来装饰方法
class Decorator:
def __init__(self,func):
self.func = func
def __call__(self,*args,**kwargs):
# 装饰内容
self.func(*args,**kwargs)
# 装饰内容
@Decorator
def func(a,b):
print(a+b)
7. 举例
这是一个验证码的例子
import random
# 从字符表中随机抽取指定位数组成验证码
def generator_code(length):
code = ''
ss = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMzxcvbnmasdfghjklpoiuytrewq'
for i in range(length):
ran = random.choice(ss)
code += ran
pass
print("本次的验证码为:", code)
pass
现在要求在生成验证码之前,校验权限码。权限码正确,输出生成的验证码;权限码错误,输出错误提示。利用装饰器完成
import random
# 装饰器代码,实现权限码验证
def genc_check(func): # 此处func传入功能函数-->func = generator_code
def inner_genc_check(*args,**kwargs): # 利用可变参数保证通用性
flag = input('确认使用权限:')
if flag == '0070270': # 判断使用权限,正确则调用功能函数
func(*args,**kwargs) # 调用功能函数并传入实参
else:
print('权限验证失败!')
pass
pass
return inner_genc_check
@genc_check # 利用装饰器进行装饰
def generator_code(length): # 功能函数
code = ''
ss = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMzxcvbnmasdfghjklpoiuytrewq'
for i in range(length):
ran = random.choice(ss)
code += ran
pass
print("本次的验证码为:", code)
pass
其他知识
1. 引用计数
方法 sys.getrefcount(a)
,需要 import sys
对a进行引用计数,真实值为返回结果-1,原因是在使用该方法时传入a,也会让a的引用计数+1
2. 开放封闭原则
开放:对于拓展是开放的
任何一个程序,不可能在设计之初就确定好所有的功能,并且在未来漫长的应用和维护过程中不许要做出任何的更新和修改。因此开发者必须允许代码拓展,添加新的功能。
封闭:对于修改是封闭的
我们写的函数可能已经在各种地方被各种人所实用,如果我们此时对其进行修改,可能会影响正在使用该函数的用户。