装饰器进阶
1.装饰器有参数(方便控制是否装饰)
import time FLAG=False #在装饰器中传一个参数,控制是否加上装饰 def timeer_out(flag): def time2(f): # 传入的实际上是func1函数的内存地址 def inner(*args, **kwargs): if flag==True: startx = time.time() ret = f(*args, **kwargs) endx = time.time() print(endx - startx) return ret else: ret = f(*args, **kwargs) return ret return inner return time2 @timeer_out(FLAG) #time2=timeer_out(FLAG) def func2(a): print(a) list1 = [1, 2, 3, 4, 5] s = int(input("请输入一个值:")) list1.append(s) for i in list1: print(i, end=' ') print('\n') return list1 #func2=time2(func2) #使用闭包 @timeer_out(FLAG) def peinrx(): print("cccccc") time.sleep(0.1) a='开始:' ret=func2(a) print(ret) peinrx()
2.多个装饰器装饰同一个函数
def wrapper1(func): def inner(*args,**kwargs): print('装饰1之前') func() print("装饰1之后") return inner def wrapper2(func): def inner(*args,**kwargs): print("装饰2之前") func() print("装饰2之后") return inner # @wrapper2 # @wrapper1 # def f(): # print("被装饰的函数") # # f() # 装饰2之前 # 装饰1之前 # 被装饰的函数 # 装饰1之后 # 装饰2之后 @wrapper1 @wrapper2 def f(): print("被装饰的函数") f() # 装饰1之前 # 装饰2之前 # 被装饰的函数 # 装饰2之后 # 装饰1之后
3.一个简单的爬取网页的示例
本来是不需要自己创建那个文件的,f=open那一行,但不知为何我的pycharm会报错,无奈之下先这么写了
import os from urllib.request import urlopen def cache(func): def inner(*args,**kwargs): #判断 if os.path.getsize('webcache'): #判断是否已经有函数 with open('webcache', "rb") as f: return f.read() ###### ret=func(*args,**kwargs) with open('webcache',"wb") as f: f.write(b'---'+ret) #已经存在的,所以 return ret return inner @cache def get(url): code=urlopen(url).read() #这是一个bytes return code f=open('webcache',"ab") f.close() ret=get('http://www.baidu.com') print(ret) ret=get('http://www.baidu.com') print(ret) ret=get('http://www.baidu.com') print(ret) ret=get('http://www.baidu.com') print(ret) ret=get('http://www.sanguosha.com') print(ret)
4.第二个示例
#1.编写装饰器,为多个函数加上认证的功能,(用户的账号密码来源于文件)。
要求成功登陆一次,后续的函数无需输入用户名和密码 #只能创建一个全局变量,否则add和del切换就要在输入
#2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
FLAG=False def login(func): def inner(*args,**kwargs): global FLAG '''登陆程序''' if FLAG: #如果已经是登陆成功了,就先走了,不需要输入 with open('log','a',encoding='utf-8') as f: f.write(func.__name__+'\n') ret = func(*args, **kwargs) return ret else: username=input("用户名:") password=input("密码:") if username=='usern' and password=='passw': FLAG=True with open('log', 'a', encoding='utf-8') as f: f.write(func.__name__ + '\n') ret=func(*args,**kwargs) return ret else: print("登陆失败!") return inner @login def shoplist_add(): print("增加一件物品") @login def shoplist_del(): print("删除一件物品") while(1): a=int(input("请选择操作 1.增加 2.删除 3.退出\n")) if a==1: shoplist_add() elif a==2: shoplist_del() elif a==3: break
5.再来一个示例。
介绍两个函数__name__和__doc__
#记现象 #functools.wraps #带参数的装饰器 #多个装饰器装饰同一个函数 #有很多个函数都用装饰器装饰过了,现在要全部去掉装饰,然后又重新再加上装饰 # def outer(*args,**kwargs): # print(args) # print(*args) # # # outer(1,2,[1,2],3,4,**{'name':9}) #outer(*[1,2,3,4]) #outer( # # (1, 2, 3, 4) # 1 2 3 4 第二个变成散的 #接收就是聚合,使用就要打散,**kwargs,用*kwargs就是打散 flag1=1 from functools import wraps def wrapper(func): @wraps(func) #给内部的函数装饰一下,使holiday()原函数仍然存在。就和inner有区别 def inner(*args,**kwargs): print("之前") ret=func(*args,**kwargs) print("之后") return ret return inner @wrapper def holiday(day): x=input("你想放几天假?") print("不是放%s天假,而是一共放%s天假"%(day,x)) return x ret=holiday(2) print(ret) print(holiday.__name__) falg2=2 # # def func2(): # #打印 # ''' # 只要胆子大,天天都是假 # :return: # ''' # print("cccc") # # print(func2.__name__) #查看函数名 # print(func2.__doc__) #查看注释