一、装饰器的认识
- 在不改变原被装饰的函数的源代码以及调用方式情况下,为其添加新的功能。
- 完全遵循开放封闭原则
- 装饰器的本质就是闭包
# 标准版装饰器
def wrapper(f): # f 是传入的被装饰的函数名
def inner(*args, **kwargs): # 传入被装饰的函数的参数
'''添加额外功能,执行被装饰函数之前的操作'''
ret = f(*args, **kwargs) # 执行被装饰的函数,并获取被装饰函数的返回值
'''添加额外功能,执行被装饰函数之后的操作'''
return ret
return inner
@wrapper
def func():
pass
func()
- 装饰器实现功能的分析
1.我们给这个测试函数加一个装饰器,计算执行这个函数需要的时间
# step1:
import time
def test_func(): # 这是需要被装饰的函数
time.sleep(1)
print('this is a test function')
# 我们给这个测试函数加一个装饰器,计算执行这个函数需要的时间
def wrapper(f):
start_time = time.time()
f()
end_time = time.time()
print(end_time - start_time)
wrapper(test_func)
# 但是装饰器要符合开放封闭原则,并且被装饰函数的调用方式也改变了
2.使用闭包,实现开放封闭原则
# step2:
import time
def test_func(): # 这是需要被装饰的函数
time.sleep(1)
print('this is a test function')
# 使用闭包,实现开放封闭原则
def wrapper(f):
# f = wrapper(test_func) # f就是一个闭包中的自由变量
def inner():
start_time = time.time()
f()
end_time = time.time()
print(end_time - start_time)
return inner
# wrapper(test_func)() # 想要执行被装饰函数,就要执行inner(),而wrapper(test_func)返回的就是inner
test_func = wrapper(test_func) # 使用赋值,让函数执行方式不改变
test_func() # 实际上就是执行inner()
3.python 进行了优化,这里可以这样写
# step3:
import time
# 使用闭包,实现开放封闭原则
def wrapper(f):
def inner():
start_time = time.time()
f()
end_time = time.time()
print(end_time - start_time)
return inner
@wrapper # 相当于test_func = wrapper(test_func)
def test_func(): # 这是需要被装饰的函数
time.sleep(1)
print('this is a test function')
test_func() # 实际上就是执行inner()
4.当被装饰函数有返回值时,要在inner函数中返回被装饰函数的返回值
# step4:被装饰函数有返回值时,要在inner函数中返回被装饰函数的返回值
import time
# 使用闭包,实现开放封闭原则
def wrapper(f):
# f = test_func
def inner():
start_time = time.time()
ret = f()
end_time = time.time()
print(end_time - start_time)
return ret
return inner
@wrapper # 相当于test_func = wrapper(test_func)
def test_func(): # 这是需要被装饰的函数
time.sleep(1)
print('this is a test function')
return 'aloha'
result = test_func() # 实际上就是执行inner()
print(result)
5.当被装饰函数需要传入参数时,要在inner函数中传入对应的参数
# step5:被装饰函数需要传入参数时,要在inner函数中传入对应的参数
import time
# 使用闭包,实现开放封闭原则
def wrapper(f):
# f = test_func
def inner(*args, **kwargs):
start_time = time.time()
ret = f(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return ret
return inner
@wrapper # 相当于test_func = wrapper(test_func)
def test_func(name, age): # 这是需要被装饰的函数
time.sleep(1)
print('this is a test function')
info = f'我叫{name}, 今年{age}'
return 'aloha', info
result = test_func('jason', 18) # 实际上就是执行inner()
print(result)
二、装饰器的应用
登录认证系统
# 简单模拟博客园登录系统
# 在访问文章,照片,文件之前,需要登录账号密码
login_status = {'username': '', 'status': False}
def get_user_password(): # 获取账号密码文件
user_dic = dict()
with open('user.txt', 'r', encoding='utf-8') as f1:
for line in f1:
line_list = line.strip().split('|')
user_dic.update({line_list[0]: line_list[1]})
return user_dic
def login(): # 用户登录(三次机会)
user_dic = get_user_password()
count = 0
while count < 3:
username = input("请输入账户名:").strip()
password = input("请输入密码:").strip()
if username in user_dic and user_dic[username] == password:
print(f'{username}你好,欢迎登录博客园')
login_status['username'] = username
login_status['status'] = True
break
else:
print('账号或密码错误')
count += 1
def auth(f): # 登录认证的装饰器
def inner(*args, **kwargs):
if login_status['status']:
ret = f(*args, **kwargs)
return ret
else:
login()
ret = f(*args, **kwargs)
return ret
return inner
@auth
def article():
print('欢迎访问文章页面')
@auth
def photo():
print('欢迎访问照片页面')
@auth
def file():
print('欢迎访问文件页面')
article()
photo()
file()