一 装饰器
装饰器就是闭包函数的一种应用场景
什么是闭包函数? 我们再来回忆一下:
闭包函数:
定义在函数内部的函数, 并且该函数包含对外部函数作用域 (强调: 对全局作用域名字的引用不算闭包) 名字的引用, 该函数称为闭包函数
说到作用域我们再回忆下:
作用域:
全局范围: 内置 + 全局
全局有效, 全局存活
局部范围: 局部
局部有效, 局部存活
作用域关系是在函数定义阶段就规定死, 与调用位置无关,
也就是说, 无论函数在哪儿调用, 都必须回到当初定义函数时的位置找作用域关系
一 为何要用装饰器
- # 开放封闭原则:
- #软件一旦上线后, 就应该遵循开放封闭原则, 对修改源代码是封闭的, 对功能的扩展是开放的, 也就是我们必须找到一种解决方法:
- #能够在不修改一个功能源代码以及调用方式的前提下, 为其加上新功能.
二 什么是装饰器
- # 装饰器他人的器具, 本身可以是任意可调用对象, 被装饰者也可以是任意可调用对象
- # 强调装饰器的原则:
- #1 不修改被装饰对象的源代码
- #2 不修改被装饰对象的调用方式
- # 装饰器的目标:
- #在遵循 1 和 2 的前提下, 为被装饰对象添加上新功能
三 装饰器的使用
- # 我们现在给下面函数增加一个运行时间的功能
- import time
- def index():
- time.sleep(3)
- print('welcome to index page')
- # 修改一
- def index():
- start_time=time.time()
- time.sleep(3)
- print('welcome to index page')
- stop_time=time.time()
- print('run time is %s' %(stop_time-start_time))
- index() #功能实现
- # 评语: 直接改源代码, 这么搞被开了
- # 再来一位童靴, 来实现功能
- # 修改二
- import time
- def index():
- time.sleep(1)
- print('welcome to index page')
- start_time=time.time()
- index()
- stop_time = time.time()
- print('run time is %s' % (stop_time - start_time))
- # 评语: 有好多函数要实现这个功能, 写 N 遍变这个代码,
- # 后期维护一脸懵逼, 还是被开
- # 再来一位童靴, 功能重复实现看我用强大的函数
- # 修订三:
- import time
- def index():
- time.sleep(3)
- print('welcome to index page')
- def wrapper(func): #func=index
- start_time=time.time()
- func() #index()
- stop_time = time.time()
- print('run time is %s' % (stop_time - start_time))
- wrapper(index)
- # 评语: 修改了原函数的调用方式, 依然被开
- # 终于来了位小牛的童靴, 函数的值可以返回, 然后我再把重新定义 index
- # 修订四:
- import time
- def index():
- time.sleep(3)
- print('welcome to index page')
- def outter(func): #func = 最原始的 index
- # func = 最原始的 index
- def wrapper():
- start_time=time.time()
- func()
- stop_time=time.time()
- print(stop_time-start_time)
- return wrapper
- index=outter(index) # 新的 index=wrapper
- index() #wrapper() 功能基本实现
- # 评语: 在原值没有返回值是没问题, 但是有返回值的情况下, 这么搞就会发现返回的是 None
- # 这次小牛牛童靴路过看到这情况, say 这么搞!
- # 修订五
- import time
- def index():
- time.sleep(1)
- print('welcome to index page')
- return 123 #假使这里返回 123 返回值可以是任意类型
- #============== 下面就是装饰器
- def timmer(func):
- #func = 最原始的 index
- def wrapper(*args,**kwargs): #可变长参数
- start_time=time.time()
- res=func(*args,**kwargs) #调用最原始的 index
- stop_time=time.time()
- print(stop_time-start_time)
- return res #index()运行的返回值
- return wrapper
- index=timmer(index) # 新的 index=wrapper
- print(index()) #功能已经实现, 返回值 123
- # 评语: 这里的装饰的功能已经实现, 返回的值也得到, 小牛牛不是白叫的
- # 天上五彩红光, 大牛童靴出现! 各位童靴火速围观!
- import time
- def timmer(func):
- def wrapper(*args,**kwargs):
- start_time=time.time()
- res=func(*args,**kwargs)
- stop_time=time.time()
- print(stop_time-start_time)
- return res
- return wrapper
- @timmer #index=timmer(index) 装饰器的标准格式!
- def index():
- time.sleep(1)
- print('welcome to index page')
- return 123
- @timmer # home=timmer(home)
- def home(name):
- time.sleep(2)
- print('welcome %s to home page' %name)
- # index()
- #home('egon')
- # 评语: 大牛就是大牛! 大牛 say: 教你们绝技, 不会的童靴可以照下面的模板实现:
- # 无参装饰器模板
- def outer(func): #outer,inner 名字功能随意
- def inner(*args,**kwargs):
- res=func(*args,**kwargs)
- return res
- return inner
- @outer #装饰器要在装饰函数的上方
- def duoduo():
- pass
四 装饰器语法
- # 被装饰函数的正上方, 单独一行
- @deco1
- @deco2
- @deco3
- def foo():
- pass
- #foo=deco1(deco2(deco3(foo)))
- # 这里的思想就是最上面装饰器, 装饰的下面所有的函数(deco2,deco3,foo)
- # 然后 deco2 装饰(deco3,foo), 最后 deco3 装饰 foo
- # 功能的不同, 放的顺序也要注意, 不然装饰的效果可能实现的就不对了!
五多个装饰器的使用:
- import time
- current_user={
- 'username':None,
- # 'login_time':None
- }
- def auth(func):
- # func=index
- def wrapper(*args,**kwargs):
- if current_user['username']: #这里是认证过的, 下次就不用认证
- print('已经登陆过了')
- res=func(*args,**kwargs)
- return res
- uname=input('用户名>>:').strip()
- pwd=input('密码>>:').strip()
- if uname == 'egon' and pwd == '123':
- print('登陆成功')
- current_user['username']=uname
- res=func(*args,**kwargs)
- return res
- else:
- print('用户名或密码错误')
- return wrapper
- def timmer(func):
- def wrapper(*args,**kwargs):
- start_time=time.time()
- res=func(*args,**kwargs)
- stop_time=time.time()
- print(stop_time-start_time)
- return res
- return wrapper
- @timmer # timmer 统计的是 auth+index 的执行时间
- @auth #我们只装饰 index 的话就要把 @timmer 紧跟 index
- def index():
- time.sleep(1)
- print('welcome to index page')
- return 123
- @auth
- @timmer #这里统计的就是 home 运行的时间
- def home(name):
- time.sleep(2)
- print('welcome %s to home page' %name)
- #index()
- #home("duoduo")
六有参数的装饰器的使用:
- import time
- current_user={
- 'username':None,
- # 'login_time':None
- }
- def auth(engine): #道理还是那个道理, 在外面包了一层 engine 的值
- # engine='file' #这个值外面穿什么进来就是什么
- def auth2(func):
- # func=index
- def wrapper(*args,**kwargs):
- if engine == 'file':
- if current_user['username']:
- print('已经登陆过了')
- res=func(*args,**kwargs)
- return res
- uname=input('用户名>>:').strip()
- pwd=input('密码>>:').strip()
- if uname == 'egon' and pwd == '123':
- print('登陆成功')
- current_user['username']=uname
- res=func(*args,**kwargs)
- return res
- else:
- print('用户名或密码错误')
- elif engine == 'mysql': #engine 值得判断情况
- print('基于 MyQL 的认证')
- elif engine == 'ldap':
- print('基于 LDAP 的认证')
- return wrapper
- return auth2 #这里也要返回 auth2 的内存地址
- @auth('ldap') #@auth2 #index=auth2(index) #index=wrapper
- def index():
- time.sleep(1)
- print('welcome to index page')
- return 123
- index() # wrapper()
来源: https://www.cnblogs.com/ManyQian/p/8670190.html