装饰器
装饰器的主要功能:
在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器的固定格式:
#装饰器的本质 :闭包函数 #功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能 def timmer(func): def inner(*args,**kwargs): '''添加函数调用之前的扩展代码''' ret = func(*args,**kwargs) '''添加函数调用之后的扩展代码''' return ret return inner
语法:在被装饰对象的正上方的单独一行,使用@语法糖可以直接调用函数装饰器
设计模式
原则 开放封闭原则
#对扩展是开放的
#对修改是封闭的
1.对扩展是开放的
为什么要对扩展开放呢?
我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
import time def wrapper(func): # 装饰 def inner(*args, **kwargs): start = time.time() ret = func(*args, **kwargs) end = time.time() print(end - start) return ret return inner @wrapper def 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 @login def fun(): print("123") print("456") fun() @login def check(): print("789")
带参数的装饰器
def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner @timer def func1(a): print(a) func1(1) 装饰器——带参数的装饰器
import time def 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 time def 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 inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f() 多个装饰器装饰同一个函数
实例
#带参数的装饰器 开关 # F = True F = False def 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 == inner def hahaha(): print('hahaha') @outer(F) #shuangww = outer(shuangww) def shuangww(): print('shuangwaiwai') shuangww() hahaha()
''' 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'))