装饰器
一:楔子
假如有一个函数,实现返回两个数的较大值:
ef my_max(x,y): m = x if x>y else y return m bigger = my_max(10,20) print(bigger)
20
二:装饰器的形成
装饰器的本质:一个闭包函数(自由变量就是装饰的函数名)。
装饰器的功能:在不修改原函数及其调用的方式的情况下对原函数功能进行扩展。
装饰器的格式:
def timer(func): def inner(*args,**wkargs): #--执行函数之前要做的--- re = func(*args,**wkargs) #--执行函数之后要做的-- return re return inner
三:语法糖
mport time #1 def timer(func2): #2 def inner(*args,**kwargs): #4 start=time.time() #5 re =func2(*args,**kwargs) #7 print(time.time()-start) #8 return re #11 return inner #12 @timer #--func2=timer(func2) #3 def func2(a): print('in func2 and get a:%s'%(a)) #9 return 'func2 over' #10 func2() #6
四:开放闭封原则。
1:对扩展开放
允许代码扩展,添加新功能。
2:对修改封闭
我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美遵循开放闭封原则。
五:带参数的装饰器。
# def outer(flag): # def timer(func): # def inner(*args,**kwargs): # if flag: # print('''执行函数之前要做的''') # re = func(*args,**kwargs) # if flag: # print('''执行函数之后要做的''') # return re # return inner # return timer # # @outer(False) # def func(): # print(111) # func('')
六;多个装饰器装饰同一函数。
ef wrapp1(func): def inner(): print('----------') func() return inner def wrapp2(func): def inner(): print('-------') func() return inner() def func(): print('------') func()
作业:
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件), 要求登录成功一次,后续的函数都无需再输入用户名和密码 注意:从文件中读出字符串形式的字典, 可以用eval('{"name":"egon","password":"123"}')转成字典格式 ''' # user_dict = { # 'pang':'123456', # 'panda':'binbin', # 'nezha':'101010' # } # print(type(user_dic)) auth_status = { 'user':None, 'status':False } def auth(func): def inner(*args,**kwargs): if auth_status['status']: ret = func(*args, **kwargs) # index/home return ret else: username = input('username : ').strip() password = input('password : ').strip() # 读文件获取用户信息 f = open('conf') user_info = f.read() user_dic = eval(user_info) if user_dic.get(username) and user_dic[username] == password: print('login successful') auth_status['user'] = username auth_status['status'] = True ret = func(*args,**kwargs) #index/home return ret else: print('login failed') return inner @auth def index(): print("欢迎来到首页") @auth def home(): print("欢迎回家") index() index() home() index()
''' 进阶作业(选做): 1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果 2.编写装饰器,实现缓存网页内容的功能: 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0), 就优先从文件中读取网页内容,否则,就去下载,然后存到文件中 ''' url_l = [] from urllib.request import urlopen def get_cache(func): def inner(*args,**kwargs): url = args[0] filename = str(hash(url)) if url in url_l: f = open(filename,'rb') ret = f.read() else: url_l.append(url) ret = func(*args, **kwargs) f = open(filename,'wb') f.write(ret) f.close() return ret return inner @get_cache def get(url): return urlopen(url).read() print(get('http://www.cnblogs.com/linhaifeng')) print(get('http://www.cnblogs.com/linhaifeng')) print(get('http://www.cnblogs.com/linhaifeng')) print(get('http://www.cnblogs.com/linhaifeng')) print(get('http://www.cnblogs.com/linhaifeng'))