目录
- 装饰器
- 1、定义
- 2、原则
- 3、装饰器核心思想
- 4、装饰器简易版本
- 5、解决有参函数问题
- 6、解决返回值问题
- 7、装饰器模板
- 8、认证装饰器
- 9、装饰器语法糖
- 单层语法糖(重难点)
- 双层语法糖(重难点)
- 三层语法糖(难点)
- 10、装饰器修复技术
- 11、有参装饰器
装饰器
本文讲述了装饰器由简易装饰器到完整装饰器的过程,一个段落解决一个问题!
1、定义
- 器:指的是工具
- 装饰:给被装饰对象添加额外的功能
2、原则
开放封闭的原则
- 开放:对扩展开放
- 封闭:对修改封闭
3、装饰器核心思想
在不改变被“装饰”对象内部代码和原有调用方式的基础之上添加额外的功能。
代码语言:javascript复制实例如下:
# 计算程序的执行时间
import time
# 获取的结果叫时间戳(运行代码的那一刻距离1970-1-1所经历的秒数)
print(time.time())
def index():
time.sleep(3)
print('计算时间停止了3秒后的结果!')
# 统计开始时间
start_time = time.time()
index()
# 统计结束的时间
end_time = time.time()
# 输出时间差
print(end_time-start_time)
# 时间运行的时间
print(end_time-start_time-3)
4、装饰器简易版本
代码语言:javascript复制实例如下: 使用闭包函数实现
import time
# 定义普通无参函数
def func():
time.sleep(2)
print('正在执行func函数')
def get_func_name(func_name):
# 将参数写入形参,可以灵活传参
# func_name = func
# 构造一个能够计算函数运行时间的闭包函数
def get_time():
# 获取开始时间
start_time = time.time()
# 调用函数
func_name() # func_name()就是func()
# 查看func_name指向的是哪个函数,方便理解
print('func_name指向的是>>>:',func_name)
# 获取结束时间
end_time = time.time()
# 打印运行时间
print("函数执行时间为{0}".format(end_time-start_time))
# 获取返回值
print('get_time指向的是>>>:',get_time)
return get_time # 这里其实是把func
# 调用get_func_name函数,传参,res接收返回结果,返回值为get_time
res = get_func_name(func)
res()
# 获取res指向的是那个函数
print('res指向的是>>>:',res)
5、解决有参函数问题
代码语言:javascript复制由于简易版本的装饰器,只能装饰无参函数,为了让有参函数也能够被装饰,需要改进简易版本 实例如下:
import time
# 定义一个无参函数
def non_argument():
time.sleep(1)
print('执行的是无参函数')
# 定义一个有参函数
def have_argument(*args,**kwargs):
time.sleep(1)
print('执行的是有参函数,参数为:',*args,**kwargs)
def get_func_name(func_name):
# func_name = non_argumengt
def get_time(*args,**kwargs):
start_time = time.time()
func_name(*args,**kwargs)
end_time = time.time()
print('函数运行时间为:',end_time-start_time)
return get_time
#调用无参函数
non_argument = get_func_name(non_argument)
non_argument() # 这里的non_argument()其实指向的是get_time
# 打印查看一下,指向的是谁,此non_argument()非彼non_argument
print(non_argument)
# 调用有参函数
have_argument = get_func_name(have_argument)
have_argument('hammer',18)
6、解决返回值问题
代码语言:javascript复制为了解决能够装饰有返回值的有参、无参函数,计算它们的运行时间,升级装饰器为可以装饰有参、无参带返回值的装饰器,改进装饰器版本。 实例如下:
import time
# 定义一个无参函数
def non_argument():
time.sleep(1)
print('执行的是无参函数')
return 'from non_argument'
# 定义一个有参函数
def have_argument(*args,**kwargs):
time.sleep(1)
print('执行的是有参函数,参数为:',*args,**kwargs)
return 'from have_argument'
# 现在可以计算有参、无参、有返回值的函数执行时间
def get_func_name(func_name): # func_name = non_argumengt
def get_time(*args,**kwargs):
start_time = time.time()
# 用get_return 接收被装饰函数的返回值
get_return = func_name(*args,**kwargs)
end_time = time.time()
print('函数运行时间为:',end_time-start_time)
# 返回被装饰函数的返回值
return get_return
return get_time
# 调用装饰器,打印被装饰函数的运行时间,和返回值
non_argument = get_func_name(non_argument)
print(non_argument())
have_argument = get_func_name(have_argument)
print(have_argument())
返回值解决后,就会推出一个固定的格式,外层获取函数名不能改变,内层获取被装饰的参数( * args, * kwargs)不用改变。*
7、装饰器模板
代码语言:javascript复制装饰器经过多版本的升级,发现了一个规律,推出装饰器模板 实例如下:
def get_func_name(func_name): # func_name = 函数名
def get_time(*args,**kwargs):
# 写入被装饰前的代码体
'''代码体'''
# 用get_return 接收被装饰函数的返回值
get_return = func_name(*args,**kwargs)
# 写入被装饰后的代码体
'''代码体'''
# 返回被装饰函数的返回值
return get_return
return get_time
8、认证装饰器
代码语言:javascript复制简易版认证装饰器:
'''
在调用sign之前需要用户输入用户名和密码
正确才可以调用
错误直接拒绝
'''
import time
def sign():
time.sleep(1)
print('sign is running')
return 'from sign'
def get_func_name(func_name):
def get_func_argument(*args, **kwargs):
username = input('please input your name>>>:').strip()
password = input('please input your pwd>>>:').strip()
if username == 'hammer' and password == '123':
get_return = func_name(*args, **kwargs)
print('>>>>>success!')
else:
print('>>>>>failure!')
return get_return
return get_func_argument
sign = get_func_name(sign)
print(sign())
代码语言:javascript复制多函数复杂认证装饰器:认证一个函数后面的函数不需要认证 实例如下:
import time
def sign():
time.sleep(1)
print('sign is running')
return 'from sign'
def login():
time.sleep(1)
print('login is running')
return 'from login'
def shopping():
time.sleep(1)
print('shopping is running ')
return 'from shopping'
# 定义一个用于记录用户是否登录的数据,全局标志
is_login = {'is_login':False}
# 构造一个装饰器
def get_func_name(func_name):
def get_func_argument(*args, **kwargs):
# 判断用户是否登录
# 登录过就直接运行被装饰的函数
if is_login.get('is_login'):
get_return = func_name(*args, **kwargs)
print('>>>>>success!')
return get_return
username = input('please input your name>>>:').strip()
password = input('please input your pwd>>>:').strip()
if username == 'hammer' and password == '123':
get_return = func_name(*args, **kwargs)
# 用户如果登录成功将登录状态改成True
is_login['is_login']= True
print('>>>>>success!')
return get_return
else:
print('>>>>>failure!')
# return get_return
return get_func_argument
sign = get_func_name(sign)
sign()
login = get_func_name(login)
login()
shopping = get_func_name(shopping)
shopping()
9、装饰器语法糖
格式:@装饰器 原理:会将下面紧贴的函数当成被装饰的对象 语法糖执行顺序:****被装饰的对象如果有多层语法糖,装饰的顺序由下向上
实例如下: eg:# @get_func_name 相当于 函数名()= get_func_name(函数名)
单层语法糖(重难点)
代码语言:javascript复制import time
# 现在可以计算有参、无参、有返回值的函数执行时间
def get_func_name(func_name): # func_name = non_argumengt
def get_time(*args,**kwargs):
start_time = time.time()
# 用get_return 接收被装饰函数的返回值
get_return = func_name(*args,**kwargs)
end_time = time.time()
print('函数运行时间为:',end_time-start_time)
# 返回被装饰函数的返回值
return get_return
return get_time
# 定义一个无参函数
@get_func_name
# @get_func_name 相当于 函数名= get_func_name(函数名)
def non_argument():
time.sleep(1)
print('执行的是无参函数')
return 'from non_argument'
non_argument()
双层语法糖(重难点)
代码语言:javascript复制实例如下:
# 统计函数运行时间
import time
def get_time(func):
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs) # 执行被装饰的函数
end_time = time.time()
print('函数执行时间:%s'%(end_time-start_time))
return res # 将被装饰函数执行之后的返回值返回
return inner
# 校验用户登录装饰
def login_auth(func):
def inner(*args, **kwargs):
# 1.先获取用户的用户名和密码
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 2.校验用户名和密码是否正确
if username == 'jason' and password == '123':
res = func(*args, **kwargs) # 执行被装饰的函数
return res # 将被装饰函数执行之后的返回值返回
print('用户名或密码错误 无权限执行')
return inner
@login_auth
@get_time # get_time
def index():
time.sleep(1)
print('from index')
index()
三层语法糖(难点)
代码语言:javascript复制实例如下:
# 判断七句print执行顺序
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('from index')
# 结果
加载了outter3
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
- 自己总结了一句话,在多层语法糖中,想要知道运行的顺序,一句话概括,外层局部函数由下向上执行,内层闭包函数由上向下执行,最后执行被装饰函数中的代码!~(个人理解不喜勿喷)
- 装饰器由下往上,遇到最后一个语法糖才会使用与函数名相同的变量名(被装饰函数)
10、装饰器修复技术
- 定义:装饰器修复技术,为了更好的掩藏被装饰对象更不被容易被察觉出用了装饰器。将返回的装饰器id换成真正函数id地址!
- 格式:
- from functools import wraps
- @wraps(函数名)
代码语言:javascript复制实例如下:
import time
from functools import wraps
# 现在可以计算有参、无参、有返回值的函数执行时间
def get_func_name(func_name): # func_name = non_argumengt
@wraps(func_name)
def get_time(*args,**kwargs):
start_time = time.time()
# 用get_return 接收被装饰函数的返回值
get_return = func_name(*args,**kwargs)
end_time = time.time()
print('函数运行时间为:',end_time-start_time)
# 返回被装饰函数的返回值
return get_return
return get_time
# 定义一个无参函数
@get_func_name
def non_argument():
time.sleep(1)
print('执行的是无参函数')
return 'from non_argument'
# 定义一个有参函数
@get_func_name
def have_argument(*args,**kwargs):
time.sleep(1)
print('执行的是有参函数,参数为:',*args,**kwargs)
return 'from have_argument'
non_argument()
have_argument()
'''如果不写修复技术,调用装饰器打印的id地址为get_time()的id地址,写了之后查看id为被装饰函数的id地址'''
11、有参装饰器
代码语言:javascript复制实例如下:
def outer(source_data):
# source_data = 'file'
def login_auth(func):
def auth(*args,**kwargs):
# 2.校验用户名和密码是否正确
# 数据的校验方式可以切换多种
if source_data == 'file':
# 从文件中获取用户数据并比对
print('file文件获取')
elif source_data == 'MySQL':
# 从MySQL数据库中获取数据比对
print('MySQL数据库获取')
elif source_data == 'postgreSQL':
# 从postgreSQL数据库中获取数据对比
print('postgreSQL数据库获取')
else:
print('用户名或密码错误 无法执行函数')
return auth
return login_auth
@outer('file')
def index():
print('from index')
@outer('MySQL')
def home():
print('from home')
index()
home()