1、装饰器介绍与简单实现python
什么是装饰器
器:指的是具有某一功能的工具
装饰:指的是为被装饰器对象添加新功能
装饰器就是用来为被装饰器对象添加新功能的工具
注意:装饰器自己能够是任意可调用对象,被装饰器的对象也能够是任意可调用对象
2. 为什么要用装饰器
开放封闭原则:封闭指的是对修改封闭,对扩展开放
装饰器的实现必须遵循两大原则:
1. 不修改被装饰对象的源代码
2. 不修改被装饰器对象的调用方式
装饰器的目标:就是在遵循1和2原则的前提下为被装饰对象添加上新功能
3. 怎么用装饰器mysql
import time def index(): print('welcome to index page') time.sleep(2) def outter(func): # func=最原始那个index的内存地址 def wrapper(): start=time.time() func() #最原始的那个index的内存地址() stop=time.time() print('run time is %s' %(stop - start)) return wrapper index=outter(index) #index=outter(最原始那个index的内存地址) #index=wrapper的内存地址 index() #wrapper的内存地址() ------------------------------------- welcome to index page run time is 2.0003037452697754
例1:(无参装饰器)sql
import time def outter(func): # func=最原始那个index的内存地址 def wrapper(): start=time.time() func() #最原始的那个index的内存地址() stop=time.time() print('run time is %s' %(stop - start)) return wrapper #@outter # 语法糖 等于 但 语法格式是 index=outer(index)要写在被装饰函数的下面 def index(): print('welcome to index page') time.sleep(3) index = outter(index) #没有语法糖的须要写在装饰器与函数下面 index()
例二、(无参装饰器)缓存
import time def outter(func): # func 表示的是Index 的函数当参数来用 def wrapper(*args,**kwargs): start=time.time() func(*args,**kwargs) # 这里其实用的就是index() stop=time.time() print('run time is %s' %(stop - start)) return wrapper @outter # 有语法糖必须写在装饰器与函数的中间 def index(x): # 例如:(写活,不要写死,例如要传递参数x) 若是函数中须要传递参数,那么就须要在装饰器中接受加参数来接受 print('welcome to index page') time.sleep(2) index(1)
2、装饰器升级版闭包
import time def index(): print('welcome to index page') time.sleep(3) def home(name): print('welcome %s to home page' %name) time.sleep(2) return 123 def timmer(func): #func=最原始那个home函数的内地址 def wrapper(*args,**kwargs): #args=('egon',) kwargs={} start=time.time() res=func(*args,**kwargs) #最原始那个home函数的内地址('egon') stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper # index=timmer(index) index() home=timmer(home) #home=outter(最原始那个home函数的内地址) #home=wrapper函数的内地址 res=home('egon') # res=wrapper函数的内地址('egon') print(res) --------------------------------------------------------------------------------------------------- welcome to index page welcome egon to home page run time is 2.000187635421753 123
3、装饰器的语法糖app
# 装饰器的语法糖:在被装饰对象正上方单独一行写@装饰器的名字
# 运行原理:ide
python解释器一旦运行到@装饰器的名字,就会调用装饰器,而后将被装饰函数的内存地址看成参数
#传给装饰器,最后将装饰器调用的结果赋值给原函数名函数
import time def timmer(func): #func=最原始那个home函数的内地址 def wrapper(*args,**kwargs): #args=('egon',) kwargs={} start=time.time() res=func(*args,**kwargs) #最原始那个home函数的内地址('egon') stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper @timmer #index=timmer(index) def index(): print('welcome to index page') time.sleep(3) @timmer #home=timmer(home) def home(name): print('welcome %s to home page' %name) time.sleep(2) return 123 index() res=home('egon') # res=wrapper函数的内地址('egon') print(res)
import time # 装饰器模板 def outter(func): def wrapper(*args,**kwargs): #在调用函数前加功能 res=func(*args,**kwargs) #调用被装饰的\也就是最原始的那个函数 #在调用函数后加功能 return res return wrapper @outter #index=outter(index) #index=wrapper def index(): print('welcome to index page') time.sleep(3) index()
4、练习认证功能装饰器工具
import time def auth(func): def wrapper(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数 return res else: print('username or password error') return wrapper @auth # index=auth(index) #index=wrapper def index(): print('welcome to index page') time.sleep(3) index() #wrapper()
5、叠加多个装饰器url
import time def timmer(func): #func=wrapper2 def wrapper1(*args,**kwargs): start=time.time() res=func(*args,**kwargs) #res=wrapper2(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper1 def auth(func): #func=最原始的那个index的内存地址 def wrapper2(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数 return res else: print('username or password error') return wrapper2 # 解释@语法的时候是自下而上运行 # 而执行装饰器内的那个wrapper函数时的是自上而下 @timmer # index=timmer(wrapper2) #index=wrapper1 @auth # index=auth(最原始的那个index的内存地址) #index=wrapper2 def index(): print('welcome to index page') time.sleep(2) index() #wrapper1()
import time def timmer(func): print('timmer') def wrapper1(*args,**kwargs): start=time.time() res=func(*args,**kwargs) #res=wrapper2(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper1 def auth(func): print('auth') def wrapper2(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数 return res else: print('username or password error') return wrapper2 @auth # index=auth(wrapper1) #index=wrapper2 @timmer #timmer(最原始的index)返回wrapper1 def index(): print('welcome to index page') time.sleep(3) index() #wrapper2() ''' outter2 outter1 wrapper1 wrapper2 '''
6、有参装饰器
import time current_user={'username':None} # 补充:全部的数据类型的值自带布尔值,能够直接看成条件去用,只须要记住布尔值为假的那一些值便可(0,空,None) def login(engine='file'): #engine='mysql' def auth(func): #func=最原始那个index的内存地址 def wrapper(*args,**kwargs): ##若是被装饰的函数有参数须要传递,那么这里也须要接收传递的参数 if current_user['username']: print('已经登陆过了,无需再次登录') res=func(*args,**kwargs) return res if engine == 'file': inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') current_user['username']=inp_user # 在登录成功以后马上记录登陆状态 res=func(*args,**kwargs) # res=最原始那个index的内存地址(*args,**kwargs) ## 这里是被装饰函数须要传递参数时,也须要加(*args,**kwargs) return res else: print('username or password error') elif engine == 'mysql': print('基于mysql的认证机制') elif engine == 'ldap': print('基于ldap的认证机制') else: print('没法识别的认证源') return wrapper return auth @login('file') #@auth # index=auth(最原始那个index的内存地址) #index=wrapper def index(): print('welcome to index page') time.sleep(3) @login('file') def home(name): print('welcome %s to home page' %name) time.sleep(2) return 123 index() #wrapper() res=home('egon') print(res)
# 有参装饰器的模板
def outter1(x,y,z): def outter2(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper return outter2
# 无参装饰器的模板
def outter(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper
装饰器补充:
#wraps装饰器应该加到装饰器最内层的函数上 from functools import wraps import time def deco(func): @wraps(func) def wrapper(*args, **kwargs): res = func(*args, **kwargs) return res # wrapper.__name__=func.__name__ # wrapper.__doc__=func.__doc__ return wrapper @deco #index=deco(index) #index=wrapper函数的内存地址 def index(): """ index 功能 """ print('welcome to index page') time.sleep(3) print(index.__name__) print(help(index)) #index.__doc__ index() print(index.__name__) print(index.__doc__) --------------------------------------------------------------------------------- index Help on function index in module __main__: index() index 功能 None welcome to index page index index 功能
做业:
今日做业: 默写: 开闭原则 什么样的函数称为闭包 python中什么是装饰器 装饰器的两个原则 一:编写函数,(函数执行的时间是随机的) 二:编写装饰器,为函数加上统计时间的功能 三:编写装饰器,为函数加上认证的功能 四:编写装饰器,为多个函数加上认证的功能(用户的帐号密码来源于文件),要求登陆成功一次,后续的函数都无需再输入用户名和密码 注意:从文件中读出字符串形式的字典,能够用eval('{"name":"egon","password":"123"}')转成字典格式 五:编写装饰器,为多个函数加上认证功能,要求登陆成功一次,在超时时间内无需重复登陆,超过了超时时间,则必须从新登陆 六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果 七:为题目五编写装饰器,实现缓存网页内容的功能: 具体:实现下载的页面存放于文件中,若是文件内有值(文件大小不为0),就优先从文件中读取网页内容,不然,就去下载,而后存到文件中 扩展功能:用户能够选择缓存介质/缓存引擎,针对不一样的url,缓存到不一样的文件中 八:还记得咱们用函数对象的概念,制做一个函数字典的操做吗,来来来,咱们有更高大上的作法,在文件开头声明一个空字典,而后在每一个函数前加上装饰器,完成自动添加到字典的操做 九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径能够指定 注意:时间格式的获取 import time time.strftime('%Y-%m-%d %X')