本文讲述了装饰器由简易装饰器到完整装饰器的过程,一个段落解决一个问题!
开放封闭的原则
在不改变被“装饰”对象内部代码和原有调用方式的基础之上添加额外的功能。
实例如下:
# 计算程序的执行时间 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)
实例如下:
使用闭包函数实现
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)
由于简易版本的装饰器,只能装饰无参函数,为了让有参函数也能够被装饰,需要改进简易版本
实例如下:
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)
为了解决能够装饰有返回值的有参、无参函数,计算它们的运行时间,升级装饰器为可以装饰有参、无参带返回值的装饰器,改进装饰器版本。
实例如下:
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)不用改变。*
装饰器经过多版本的升级,发现了一个规律,推出装饰器模板
实例如下:
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
简易版认证装饰器:
''' 在调用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())
多函数复杂认证装饰器:认证一个函数后面的函数不需要认证
实例如下:
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()
格式:@装饰器
原理:会将下面紧贴的函数当成被装饰的对象
语法糖执行顺序:****被装饰的对象如果有多层语法糖,装饰的顺序由下向上
实例如下:
eg:# @get_func_name 相当于 函数名()= get_func_name(函数名)
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()
实例如下:
# 统计函数运行时间 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()
实例如下:
# 判断七句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
- 自己总结了一句话,在多层语法糖中,想要知道运行的顺序,一句话概括,外层局部函数由下向上执行,内层闭包函数由上向下执行,最后执行被装饰函数中的代码!~(个人理解不喜勿喷)
- 装饰器由下往上,遇到最后一个语法糖才会使用与函数名相同的变量名(被装饰函数)
定义:装饰器修复技术,为了更好的掩藏被装饰对象更不被容易被察觉出用了装饰器。将返回的装饰器id换成真正函数id地址!
格式:
实例如下:
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地址'''
实例如下:
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()
持续更新中····