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 random10 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 MyCaller18 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 page38 run time is 2.000008821487426839 welecome to HOME page40 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 random10 from functools import wraps11 12 def RunTime(TheCaller): #定义装饰器+13 @wraps(TheCaller) #可以让用户查看帮助信息的时候查看其自己的源代码定义的帮助信息。14 def MyCaller(*args,**kwargs):15 '''16 Runtime's help information17 '''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 res23 24 return MyCaller25 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 res34 else:35 print('login error')36 return Auth37 38 #被装饰函数39 # @NewAddAuth40 @RunTime #等效于index=RunTime(index),装饰器的执行顺序是自下而上。41 def Index():42 '''43 Index's help information44 '''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 information53 '''54 time.sleep(random.randrange(1,2))55 print('welecome to %s HOME page'%(name))56 return 66657 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 page70 run time is 3.00001883506774971 welecome to 尹正杰 HOME page72 run time is 1.000189065933227573 Index return :yinzhengjie74 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 res38 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'] = username45 login_dic['status'] = True46 res = func(*args, **kwargs)47 return res48 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 wrapper57 return auth58 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:yinzhengjie75 password:12376 login successful77 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 res32 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'] = username39 login_dic['status'] = True40 res = func(*args,**kwargs)41 return res42 else:43 print('login error')44 return wrapper45 46 @auth47 def Index():48 print("Welcome to Index!")49 50 @auth51 def home(name):52 print("Welecome %s to home page!"%name)53 54 Index()55 home("尹正杰")56 57 58 59 60 以上代码执行结果如下:61 username:yinzhengjie62 password:12363 login successful64 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 os10 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 res25 26 return wrapper27 28 @make_cache29 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'))
3.装饰器包装原函数案例
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 FuncDict={} 8 9 def MakeDict(key):10 def deco(func):11 FuncDict[key]=func12 # def wrapper(*args,**kwargs): #此行及以下3行可以不写,这样就可以达到隐藏你原来函数的名字。13 # res = func(*args,**kwargs)14 # return res15 # return wrapper16 return deco17 18 19 @MakeDict("one")20 def First():21 print("From Shell")22 23 24 @MakeDict("two")25 def Second():26 print("From Second")27 28 @MakeDict("three")29 def Third():30 print("From Third")31 32 print(FuncDict)33 34 while True:35 cmd = input(">>>:").strip()36 if cmd in FuncDict:37 FuncDict[cmd]()38 39 40 41 #以上代码执行结果如下:42 { 'one':, 'two': , 'three': }43 >>>:three44 From Third45 >>>:one46 From Shell47 >>>:two48 From Second49 >>>:50 >>>:51 >>>: