python中的无参装饰器和有参装饰器
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
装饰器特点:
1>.开放封闭原则,即对扩展是开放的,对修改时封闭的;
2>.装饰器本质可以是任意可调用的对象,被装饰的对象也可以是任意可调用对象;
3>.装饰器的功能是在不修改被装饰器对象源代码以及被装饰器对象的调用方式的前提下为其扩展新功能;
4>.装饰器本质是函数,(即装饰其他函数)就是为其他函数添加附加功能。
一.典型装饰器案例
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 #装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字 8 import time 9 import random 10 11 def RunTime(TheCaller): #定义装饰器 12 def MyCaller(): 13 start_time = time.time() 14 TheCaller() 15 stop_time=time.time() 16 print(‘run time is %s‘ %(stop_time-start_time)) 17 return MyCaller 18 19 #被装饰函数 20 @RunTime #等效于index=RunTime(index) 21 def index(): 22 time.sleep(random.randrange(2,4)) #可以在1-3秒钟(不包括4秒哟)随机睡眠指定范围的时长。 23 print(‘welecome to INDEX page‘) 24 25 @RunTime #home=RunTime(home) 26 def home(): 27 time.sleep(random.randrange(1,2)) 28 print(‘welecome to HOME page‘) 29 30 index() #MyCaller() 31 home() 32 33 34 35 36 #以上代码执行结果如下: 37 welecome to INDEX page 38 run time is 2.0000088214874268 39 welecome to HOME page 40 run time is 1.0006351470947266
二.多个装饰器案例展示
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 #装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字 8 import time 9 import random 10 from functools import wraps 11 12 def RunTime(TheCaller): #定义装饰器+ 13 @wraps(TheCaller) #可以让用户查看帮助信息的时候查看其自己的源代码定义的帮助信息。 14 def MyCaller(*args,**kwargs): 15 ‘‘‘ 16 Runtime‘s help information 17 ‘‘‘ 18 start_time = time.time() 19 res = TheCaller(*args,**kwargs) 20 stop_time=time.time() 21 print(‘run time is %s‘ %(stop_time-start_time)) 22 return res 23 24 return MyCaller 25 26 def NewAddAuth(TheCaller): 27 def Auth(*args,**kwargs): 28 name=input(‘username: ‘) 29 password=input(‘password: ‘) 30 if name == ‘yinzhengjie‘ and password == ‘123‘: 31 print(‘login successful‘) 32 res = TheCaller(*args,**kwargs) 33 return res 34 else: 35 print(‘login error‘) 36 return Auth 37 38 #被装饰函数 39 # @NewAddAuth 40 @RunTime #等效于index=RunTime(index),装饰器的执行顺序是自下而上。 41 def Index(): 42 ‘‘‘ 43 Index‘s help information 44 ‘‘‘ 45 time.sleep(random.randrange(2,4)) #可以在1-3秒钟(不包括4秒哟)随机睡眠指定范围的时长。 46 print(‘welecome to INDEX page‘) 47 return "yinzhengjie" 48 49 @RunTime #home=RunTime(home) 50 def Home(name): 51 ‘‘‘ 52 Home‘s help information 53 ‘‘‘ 54 time.sleep(random.randrange(1,2)) 55 print(‘welecome to %s HOME page‘%(name)) 56 return 666 57 58 res1 = Index() #MyCaller() 59 res2 = Home("尹正杰") 60 print("Index return :%s"%(res1)) 61 print("Home return :%s"%(res2)) 62 # print(help(Index)) 63 # print(Index().__doc__) 64 65 66 67 68 #以上代码执行结果如下: 69 welecome to INDEX page 70 run time is 3.000018835067749 71 welecome to 尹正杰 HOME page 72 run time is 1.0001890659332275 73 Index return :yinzhengjie 74 Home return :666
三.有参装饰器
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 ‘‘‘ 8 编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登陆成功一次,后续的函数都无需再验证。 9 ‘‘‘ 10 11 12 # user_dic = { 13 # ‘yinzhengjie‘:‘123‘, 14 # ‘Golang‘:"666", 15 # ‘Python‘:"888", 16 # } 17 # 18 # with open("user.db","w",encoding="utf-8")as f: 19 # f.write(str(user_dic)) 20 21 22 23 24 db_path = "user.db" 25 26 login_dic ={ 27 ‘user‘:None, 28 "status":False, 29 } 30 31 def Decorator(AuthType="file"): 32 def auth(func): 33 def wrapper(*args, **kwargs): 34 if AuthType == "file": 35 if login_dic[‘user‘] and login_dic[‘status‘]: 36 res = func(*args, **kwargs) 37 return res 38 username = input("username:") 39 password = input("password:") 40 with open(db_path, "r", encoding="utf-8")as f: 41 user_dic = eval(f.read()) 42 if username in user_dic and password == user_dic[username]: 43 print(‘login successful‘) 44 login_dic[‘user‘] = username 45 login_dic[‘status‘] = True 46 res = func(*args, **kwargs) 47 return res 48 else: 49 print(‘login error‘) 50 elif AuthType == "ldap": 51 print("LDAP认证方式") 52 elif AuthType == "MySQL": 53 print("MySQL认证方式") 54 else: 55 print("其他认证方式") 56 return wrapper 57 return auth 58 59 @Decorator() 60 def Index(): 61 print("Welcome to Index!") 62 63 @Decorator(AuthType="MySQL") 64 def home(name): 65 print("Welecome %s to home page!"%name) 66 67 Index() 68 home("尹正杰") 69 70 71 72 73 #以上代码执行结果如下: 74 username:yinzhengjie 75 password:123 76 login successful 77 Welcome to Index! 78 MySQL认证方式
四.小试牛刀
1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登陆成功一次,后续的函数都无需再验证。
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 8 # user_dic = { 9 # ‘yinzhengjie‘:‘123‘, 10 # ‘Golang‘:"666", 11 # ‘Python‘:"888", 12 # } 13 # 14 # with open("user.db","w",encoding="utf-8")as f: 15 # f.write(str(user_dic)) 16 17 18 19 20 db_path = "user.db" 21 22 login_dic ={ 23 ‘user‘:None, 24 "status":False, 25 } 26 27 def auth(func): 28 def wrapper(*args,**kwargs): 29 if login_dic[‘user‘] and login_dic[‘status‘]: 30 res = func(*args, **kwargs) 31 return res 32 username = input("username:") 33 password = input("password:") 34 with open(db_path, "r", encoding="utf-8")as f: 35 user_dic = eval(f.read()) 36 if username in user_dic and password == user_dic[username]: 37 print(‘login successful‘) 38 login_dic[‘user‘] = username 39 login_dic[‘status‘] = True 40 res = func(*args,**kwargs) 41 return res 42 else: 43 print(‘login error‘) 44 return wrapper 45 46 @auth 47 def Index(): 48 print("Welcome to Index!") 49 50 @auth 51 def home(name): 52 print("Welecome %s to home page!"%name) 53 54 Index() 55 home("尹正杰") 56 57 58 59 60 以上代码执行结果如下: 61 username:yinzhengjie 62 password:123 63 login successful 64 Welcome to Index! 65 Welecome 尹正杰 to home page!
2.编写下载网页内容的函数,要求功能是:用户传入一个URL,函数返回下载页面的内容。
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/ 5 #EMAIL:y1053419035@qq.com 6 7 8 from urllib.request import urlopen 9 import os 10 11 cache_path=r‘cache.txt‘ 12 def make_cache(func): 13 def wrapper(*args,**kwargs): 14 if os.path.getsize(cache_path):#说明有缓存 15 print(‘\033[45m=========有缓存=========\033[0m‘) 16 with open(cache_path,‘rb‘) as f: 17 res=f.read() 18 19 else: 20 res=func(*args,**kwargs) #下载 21 with open(cache_path,‘wb‘) as f: #制作缓存 22 f.write(res) 23 24 return res 25 26 return wrapper 27 28 @make_cache 29 def get(url): 30 return urlopen(url).read() 31 32 33 print(‘============first============‘) 34 print(get(‘http://www.cnblogs.com/yinzhengjie‘)) 35 print(‘============second===========‘) 36 print(get(‘http://www.cnblogs.com/yinzhengjie‘)) 37 print(‘============third============‘) 38 print(get(‘http://www.cnblogs.com/yinzhengjie‘))