第九章:装饰器
装饰器简介
装饰器形成的过程:最简单的装饰器——有返回值的——有一个参数——万能参数
装饰器的作用:不想修改函数的调用方式,但是还想在原来的函数前后添加功能
原则:开放封闭原则
开放:对扩展是开放的
封闭:对修改是封闭的
语法糖:@装饰器函数名
本质:并不是一门新的技术 而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果
装饰器的固定模式
无参数装饰器
import time
def wrapper(f): # 装饰器函数,f是被装饰的函数
# 定义一个内置函数,且和下面统级别的返回值名字一致且不加括号
# 动态参数一定要原封不动的传给 被装饰的函数 f()
def inner(*args, **kwargs):
'''在被装饰函数之前要做的事'''
ret = f(*args, **kwargs) # 被装饰的函数 函数执行完的返回值要原封不动传给 return
'''在被装饰函数之后要做的事'''
return ret
return inner
@wrapper # 语法糖 @装饰器函数名 等价于 func = wrapper(func)
def func(a, b): # 被装饰的函数
time.sleep(0.01)
print('你好:世界', a, b)
return '新年好'
# print(func(23,45)) # 接收返回值
ret = func(23, 45) # 接收返回值
print(ret)
有参数装饰器
def outer_plus(mode):
def outer(func):
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
return outer
@outer_plus('MySQL') # outer_plus('MySQL') 表示 outer_plus('MySQL') == outer
def func(): # @ 表示 @outer 即:func == outer(func) == inner
pass
多层语法糖
def wrapper(func):
def inner(*args,**kwargs):
print("-----1-----")
ret = func(*args,**kwargs)
print("*****1*****")
return ret
return inner
def wrapper2(func):
def inner2(*args,**kwargs):
print("-----2-----")
ret = func(*args,**kwargs)
print("*****2*****")
return ret
return inner2
def wrapper3(func):
def inner3(*args,**kwargs):
print("-----3-----")
ret = func(*args,**kwargs)
print("*****3*****")
return ret
return inner3
@wrapper3
@wrapper2
@wrapper
def f():
print("in f")
return '就是这样'
print(f())
输出结果如下:
-----3-----
-----2-----
-----1-----
in f
*****1*****
*****2*****
*****3*****
就是这样
装饰器修复技术
from functools import wraps
def outer(func_name):
@wraps(func_name) # 仅仅是为了让装饰器的效果更加逼真 平时可以不写
def inner(*args, **kwargs):
"""我是inner 我擅长让人蒙蔽"""
res = func_name(*args, **kwargs)
return res
return inner
@outer
def func():
"""我是真正的func 我很强大 我很牛 我很聪明"""
pass
# help(func) # func() 我是真正的func 我很强大 我很牛 我很聪明
# print(func) # <function func at 0x0585A2B8>
func()
作业
1.编写一个用户认证装饰器
函数:register login transfer withdraw
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
提示:全局变量 记录当前用户是否认证
2.利用递归函数依次打印列表中每一个数据值
l1 = [1,[2,[3,[4,[5,[6,[7,[8,]]]]]]]]
3.利用有参装饰器编写多种用户登录校验策略
解答
# 执行每个函数的时候必须先校验身份 eg: ysg 123
flag = False
# 定义登录装饰器
def login(func):
def inner(*args, **kwargs):
global flag
# 被装饰函数之前要做的事
# 校验登录操作为装饰前要做的事
if flag:
ret = func(*args, **kwargs)
# 被装饰函数之后要做的事
return ret
else:
name = input('请输入用户名>>>').strip()
pwad = input('请输入密码>>>').strip()
if name == 'ysg' and pwad == '123':
flag = True
ret = func(*args, **kwargs)
# 被装饰函数之后要做的事
return ret
else:
print('用户校验失败')
return inner
@login # transfer = login(transfer)
def transfer():
print('进行转账')
@login
def withdraw():
print('进行取款')
transfer()
withdraw()
# 2.利用递归函数依次打印列表中每一个数据值
lit = [1, [2, [3, [4, [5, [6, [7, [8, ]]]]]]]]
new_lit = []
def list_open(lit):
for i in lit:
if isinstance(i, list):
list_open(i)
else:
new_lit.append(i)
list_open(lit)
print(new_lit)
# 3.利用有参装饰器编写多种用户登录校验策略
def val_out(val):
def outer(func):
def inner(*args, **kwargs):
if val == 'only_one':
name = input('输入用户名>>>').strip()
pawd = input('输入密码>>>').strip()
if name == 'ysg' and pawd == '123':
ret = func(*args, **kwargs)
return ret
else:
print('用户名或密码错误')
elif val == 'data_list':
lit = ['jason|123','kevin|321','tony|222']
dit = {i.split('|')[0]:i.split('|')[1] for i in lit}
name = input('输入用户名>>>').strip()
pawd = input('输入密码>>>').strip()
if name in dit and pawd == dit.get(name):
ret = func(*args, **kwargs)
return ret
else:
print('用户名或密码错误')
elif val == 'data_file':
with open(r'F:\user.txt', 'r', encoding='utf-8') as fr:
dit = {i.split('|')[0]:i.split('|')[1] for i in fr.read().splitlines()}
name = input('输入用户名>>>').strip()
pawd = input('输入密码>>>').strip()
if name in dit and pawd == dit.get(name):
ret = func(*args, **kwargs)
return ret
else:
print('用户名或密码错误')
return inner
return outer
@val_out('only_one')
def only_one():
print('直接写死的 ysg 123')
@val_out('data_list')
def data_list():
print("数据来源于列表 ['jason|123','kevin|321','tony|222']")
@val_out('data_file')
def data_file():
print('数据来源于文件 jason|123 tom|321')
only_one()
data_list()
data_file()

浙公网安备 33010602011771号