装饰器的进阶:
1、带参数的装饰器:
可以解决装饰器有时用有时不用的情形。
1 # 带参数的装饰器主要解决的问题: 2 # 如果有几百个函数,有的时候需要都加装饰器,有的时候又需要都去掉装饰器,不可能一个一个去添加和去除,带参数的装饰器就应运而生了。 3 flag = False # 只需要更改这里,就可以控制被装饰的函数是否执行额外功能 4 5 6 def wrapper_outer(flag): 7 def wrapper(func): 8 def inner(*args, **kwargs): 9 if flag: 10 print("额外的功能") 11 ret = func(*args, **kwargs) 12 return ret 13 else: 14 ret = func(*args, **kwargs) 15 return ret 16 return inner 17 return wrapper 18 19 20 # @wrapper 21 @wrapper_outer(flag) # 其实这句话相当于执行了:wrapper = wrapper_outer(flag)和@wrapper,装饰器里面并没有变化 22 def shoplist_add(): 23 print("添加一件商品") 24 25 26 # @wrapper 27 @wrapper_outer(flag) 28 def shoplist_del(): 29 print("删除一件商品") 30 31 32 # @wrapper 33 @wrapper_outer(flag) 34 def shoplist_update(): 35 print("更新一件商品") 36 37 38 shoplist_add() 39 shoplist_del() 40 shoplist_update()
2、多个装饰器装饰一个函数:
执行结果类似于套娃,执行过程需要理解。
1 def wrapper1(func): 2 def inner1(*args, **kwargs): 3 print("wrapper1", "before wrap") 4 ret = func(*args, **kwargs) 5 print("wrapper1", "after wrap") 6 return ret 7 return inner1 8 9 10 def wrapper2(func): 11 def inner2(*args, **kwargs): 12 print("wrapper2", "before wrap") 13 ret = func(*args, **kwargs) 14 print("wrapper2", "after wrap") 15 return ret 16 return inner2 17 18 19 @wrapper2 20 @wrapper1 21 def f(): # 执行结果有点像套娃,具体执行过程需要理解 22 print("in f") 23 24 25 """ 26 wrapper2 before wrap 27 wrapper1 before wrap 28 in f 29 wrapper1 after wrap 30 wrapper2 after wrap 31 """ 32 33 34 f()
3、作业:
几个新知识点:
1>os模块中,判断文件大小,可用os.path.getsize(文件名);
2>urllib模块中,可用urllib.request.urlopen().read()下载源码;
1 # 1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件), 2 # 要求登录成功一次,后续的函数都无需再输入用户名和密码 3 # flag = False 4 # 5 # 6 # def login(func): 7 # def inner(*args, **kwargs): 8 # global flag 9 # if flag: 10 # ret = func(*args, **kwargs) 11 # return ret 12 # else: 13 # username = input("username: ") 14 # password = input("password: ") 15 # if username == "eric" and password == "123": 16 # flag = True 17 # ret = func(*args, **kwargs) 18 # return ret 19 # else: 20 # print("登陆失败") 21 # return inner 22 # 23 # 24 # @login 25 # def shoplist_add(): 26 # print("添加一件商品") 27 # 28 # 29 # @login 30 # def shoplist_del(): 31 # print("删除一件商品") 32 # 33 # 34 # shoplist_add() 35 # shoplist_del() 36 37 # 2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件 38 # def log(func): 39 # def inner(*args, **kwargs): 40 # ret = func(*args, **kwargs) 41 # with open("log.txt","a", encoding="utf-8") as f: 42 # f.write(func.__name__ + "\n") 43 # return ret 44 # return inner 45 # 46 # 47 # @log 48 # def shoplist_add(): 49 # print("添加一件商品") 50 # 51 # 52 # @log 53 # def shoplist_del(): 54 # print("删除一件商品") 55 56 # shoplist_add() 57 # shoplist_del() 58 59 # 进阶作业(选做): 60 # 1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果 61 # 2.为题目1编写装饰器,实现缓存网页内容的功能: 62 # 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中 63 from urllib.request import urlopen 64 import os 65 66 67 def cache(func): 68 def inner(*args, **kwargs): 69 if os.path.getsize("web_html"): # 判断文件大小调用OS模块 70 with open("web_html", "rb") as f: 71 return f.read() # 如果文件不为空,则直接返回 72 ret = func(*args, **kwargs) 73 with open("web_html", "wb") as f: 74 f.write(b"***" + ret) 75 return ret 76 return inner 77 78 79 @cache 80 def get_url(url): 81 code = urlopen(url).read() 82 return code 83 84 85 res = get_url("http://baidu.com") 86 print(res) 87 res = get_url("http://baidu.com") 88 print(res) 89 res = get_url("http://baidu.com") 90 print(res)