1 什么是装饰器
器=>工具
装饰=>指的是为被装饰对象添加新功能
装饰器本身可以是任意可调用的对象=>函数
被装饰的对象也可以是任意可调用的对象=>函数
目标:写一个函数来为另一个函数添加新功能
2 为何要用装饰器
开放封闭原则:软件一旦上线就应该对修改封闭,对拓展开放
对修改封闭:
1.不能修改功能的源代码
2.也不能修改功能的调用方式
对拓展开放
可以为原有功能添加新功能
装饰器就是要在不修改功能源代码以及调用方式的前提下为原有功能添加新功能
3.如何用装饰器
函数无返回值
import time
def index():
print('welcome to index page;)
time.sleep(3)
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() #wraper()
函数有返回值'
import time
def index():
print('welcome to index page')
time,sleep(3)
return 123
def outter(func):
# func=最原始那个index的内存地址
def wrapper():
start=time.time()
res=func()
stop=time.time()
print('run time is %s'%(stop-start))
return res
return wrapper
index=outter(index) #index=outter(最原始那个index的内存)
res=index()
print(res)
import time
def index():
print('welcome to index page')
time.sleep(3)
return 123
def home(name)
print('welcom %s to home page'%name)
time.sleep(1)
def outter(func):
#func=最原始那个home的内存地址
def wrapper(*args,**kwargs)
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print('run time is %'%(stop-start))
return res
return wrapper
index=outter(index) #index=outter(最原始那个index的内地址) #index=wrapper函数的内地址
home=outter(home) #index=outter(最原始那个home的内地址) #home=wrapper函数的内地址
home('egon')
index()#wrapper()
@装饰器的名字:要在被装饰对象正上方单独一行写上
import time
def timmer(func): # func=最原始那个home的内存地址
def wrapper(*args,**kwargs)
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print('run time is %s"%(stop-start))
return res
wrapper.__doc__=func.__doc__
wrapper.__name__=func.__name__
return wrapper
@timmer #index=timmer(index) #index=timmer(最原始那个index的内存地址)
def index():
"""这是index功能"""
print('welcom to index page')
time.sleep(3)
return 123
@time #home=timmer(home) #index=timmer(最原始那个home的内存地址)#index=wrapper函数的内存地址
def index:
"""这是index"""
print('welcom to index page')
time.sleep(3)
return 123
@timmer
def home(name):
"""这是home功能"""
print('welcome %s to home page' %name)
time.sleep(1)
print(help(index))
print(index.__name__)
有参装饰器
无参装饰器的模板
def outter(func):
def wrapper(*args,**kwrgs):
res=func(*args,**kwargs)
return res
return wrapper
import time
user_info={'current_user':None}
def auth(func):
def wrapper(*args,**kwargs):
if user_info['current_user'] is not None:
res=func(*args,**kwargs)
return res
inp_user=input('username>>>: ').strip()
inp_pwd=input('password>>>: ').strip()
if inp_user == 'egon' and inp_pwd == '123':
# 记录登录状态
user_info['current_user']=inp_user
print('login successful')
res=func(*args,**kwargs)
return res
else:
print('user or password error')
return wrapper
@auth
def index():
"""这是index功能"""
print('welcome to index page')
time.sleep(2)
return 123
@auth
def home(name):
"""这是home功能"""
print('welcome %s to home page' %name)
time.sleep(1)
# index()
# home('egon')
# 有参装饰器
def outter2(xxx,yyy):
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
print(xxx)
print(yyy)
return res
return wrapper
return outter
import time
user_info={'current_user':None}
def auth2(engine='file'):
def auth(func):
def wrapper(*args,**kwargs):
if user_info['current_user'] is not None:
res=func(*args,**kwargs)
return res
inp_user=input('username>>>: ').strip()
inp_pwd=input('password>>>: ').strip()
if engine == 'file':
print('基于文件的认证')
if inp_user == 'egon' and inp_pwd == '123':
# 记录登录状态
user_info['current_user']=inp_user
print('login successful')
res=func(*args,**kwargs)
return res
else:
print('user or password error')
elif engine == 'mysql':
print('基于mysql数据的认证')
elif engine == 'ldap':
print('基于ldap的认证')
else:
print('无法识别认证源')
return wrapper
return auth
@auth2(engine='mysql') # @auth ===> index=auth(最原始那个index的内存地址)===》index=wrapper
def index():
"""这是index功能"""
print('welcome to index page')
time.sleep(2)
return 123
@auth2(engine='file')
def home(name):
"""这是home功能"""
print('welcome %s to home page' %name)
time.sleep(1)
index() #wrapper()
home('egon')
作业
一:编写函数,(函数执行的时间是随机的)
二:编写装饰器,为函数加上统计时间的功能
def outter(func):
def inner(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print('运行时间:%s'%(stop-start))
return res
return inner
@outter
def index():
print('hello word')
time.sleep(3)
return 123
index()
三:编写装饰器,为函数加上认证的功能
import time
def outter(func):
def inner(*args,**kwargs):
name=input('请输入用户名>>:')
pws=input('请输入密码>>:')
if name=='gongcheng' and pws=='123':
res=func(*args,**kwargs)
print('登录成功')
return res
else:
print('用户名或密码错误')
return inner
@outter
def index(name):
print('hello word')
time.sleep(3)
return 123
index()
四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式
import time
def outter(func):
def inner(*args,**kwargs):
name=input('请输入用户名>>:')
pws=input('请输入密码>>:')
with open('db.txt', mode='rt', encoding='utf-8')as f:
dict = eval(f.read())
if name==dict['name'] and pws==dict['password']:
res=func(*args,**kwargs)
print('登录成功')
return res
else:
print('用户名或密码错误')
return inner
@outter
def index():
print('hello world')
time.sleep(3)
return 123
五:编写装饰器,为多个函数加上认证功能,要求登录成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录
六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
七:为题目五编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中
八:还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作
九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径可以指定
注意:时间格式的获取
import time
time.strftime('%Y-%m-%d %X')