装饰器
装饰器的主要功能:
在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器的固定格式:
#装饰器的本质 :闭包函数#功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能def timmer(func): def inner(*args,**kwargs): '''添加函数调用之前的扩展代码''' ret = func(*args,**kwargs) '''添加函数调用之后的扩展代码''' return ret return inner
语法:在被装饰对象的正上方的单独一行,使用@语法糖可以直接调用函数装饰器
设计模式
原则 开放封闭原则
#对扩展是开放的
#对修改是封闭的
1.对扩展是开放的
为什么要对扩展开放呢?
我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
import timedef wrapper(func): # 装饰 def inner(*args, **kwargs): start = time.time() ret = func(*args, **kwargs) end = time.time() print(end - start) return ret return inner@wrapperdef lll(): time.sleep(0.1) print('hello')lll()
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
login_dic={"name":"None","passwd":"None", }with open('passwd.txt', 'r+', encoding='utf-8') as f1: f2 = eval(f1.read())def login(func): def inner(*args, **kwargs): '''判断用户名、密码是否在字典中''' if login_dic["name"]==f2["name"] and login_dic["passwd"]==f2["passwd"]: ret = func(*args, **kwargs) return ret else: name = input("请输入用户名:") passwd = input("请输入密码:") if name == f2['name'] and passwd == f2['passwd']: print("登陆成功") login_dic['name'] = name login_dic['passwd'] = passwd ret = func(*args, **kwargs) return ret else: print("输入有误,请重新输入") return inner@logindef fun(): print("123") print("456")fun()@logindef check(): print("789")
带参数的装饰器
def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner@timerdef func1(a): print(a)func1(1)装饰器——带参数的装饰器
import timedef timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner@timer #==> func1 = timer(func1)def func1(a,b): print('in func1')@timer #==> func2 = timer(func2)def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over'func1('aaaaaa','bbbbbb')print(func2('aaaaaa'))装饰器——成功hold住所有函数传参
import timedef timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner@timer #==> func2 = timer(func2)def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over'func2('aaaaaa','bbbbbb')print(func2('aaaaaa'))装饰器——带返回值的装饰器
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()带参数的装饰器格式
def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return innerdef wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner@wrapper2@wrapper1def f(): print('in f')f()多个装饰器装饰同一个函数
实例
#带参数的装饰器 开关# F = TrueF = Falsedef outer(flag): def wrapper(func): def inner(*args,**kwargs): if flag: print('before') ret = func(*args,**kwargs) print('after') else: ret = func(*args, **kwargs) return ret return inner return wrapper@outer(F) #-->@wrapper -->hahaha = wrapper(hahaha) #-->hahaha == innerdef hahaha(): print('hahaha')@outer(F) #shuangww = outer(shuangww)def shuangww(): print('shuangwaiwai')shuangww()hahaha()
'''1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果2.编写装饰器,实现缓存网页内容的功能:具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中'''url_l = []from urllib.request import urlopendef 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_cachedef 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'))