python中的无参装饰器和有参装饰器
该博客严禁抄袭: 版权所有,盗版必究!
装饰器特点:
1>.开放封闭原则,即对扩展是开放的,对修改时封闭的;
2>.装饰器本质可以是任意可调用的对象,被装饰的对象也可以是任意可调用对象;
3>.装饰器的功能是在不修改被装饰器对象源代码以及被装饰器对象的调用方式的前提下为其扩展新功能;
4>.装饰器本质是函数,(即装饰其他函数)就是为其他函数添加附加功能。
装饰器其实就是对函数的理解与运用(函数对象与闭包函数)
一 ,典型的案例:
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :rianleycheng #blog:http://www.cnblogs.com/rianley #装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字 import time import random def RunTime(TheCaller): #定义装饰器 def MyCaller(): start_time = time.time() TheCaller() stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return MyCaller #被装饰函数 @RunTime #等效于index=RunTime(index) def index(): time.sleep(random.randrange(2,4)) #可以在1-3秒钟(不包括4秒哟)随机睡眠指定范围的时长。 print('welecome to INDEX page') @RunTime #home=RunTime(home) def home(): time.sleep(random.randrange(1,2)) print('welecome to HOME page') index() #MyCaller() home() #以上代码执行结果如下: welecome to INDEX page run time is 2.0000088214874268 welecome to HOME page run time is 1.0006351470947266
二,多个装饰器的案例
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :rianleycheng #blog:http://www.cnblogs.com/rianley #装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字 import time import random from functools import wraps def RunTime(TheCaller): #定义装饰器+ @wraps(TheCaller) #可以让用户查看帮助信息的时候查看其自己的源代码定义的帮助信息。 def MyCaller(*args,**kwargs): ''' Runtime's help information ''' start_time = time.time() res = TheCaller(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return MyCaller def NewAddAuth(TheCaller): def Auth(*args,**kwargs): name=input('username: ') password=input('password: ') if name == 'rianley' and password == '123': print('login successful') res = TheCaller(*args,**kwargs) return res else: print('login error') return Auth #被装饰函数 # @NewAddAuth @RunTime #等效于index=RunTime(index),装饰器的执行顺序是自下而上。 def Index(): ''' Index's help information ''' time.sleep(random.randrange(2,4)) #可以在1-3秒钟(不包括4秒哟)随机睡眠指定范围的时长。 print('welecome to INDEX page') return "rianleycheng" @RunTime #home=RunTime(home) def Home(name): ''' Home's help information ''' time.sleep(random.randrange(1,2)) print('welecome to %s HOME page'%(name)) return 666 res1 = Index() #MyCaller() res2 = Home("程小航") print("Index return :%s"%(res1)) print("Home return :%s"%(res2)) # print(help(Index)) # print(Index().__doc__) #以上代码执行结果如下: welecome to INDEX page run time is 3.000018835067749 welecome to 程小航 HOME page run time is 1.0001890659332275 Index return :rianleycheng Home return :666
三,有参装饰器
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :rianleycheng #blog:http://www.cnblogs.com/rianley ''' 编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登陆成功一次,后续的函数都无需再验证。 ''' # user_dic = { # 'rianley':'123', # 'Golang':"666", # 'Python':"888", # } # # with open("user.db","w",encoding="utf-8")as f: # f.write(str(user_dic)) db_path = "user.db" login_dic ={ 'user':None, "status":False, } def Decorator(AuthType="file"): def auth(func): def wrapper(*args, **kwargs): if AuthType == "file": if login_dic['user'] and login_dic['status']: res = func(*args, **kwargs) return res username = input("username:") password = input("password:") with open(db_path, "r", encoding="utf-8")as f: user_dic = eval(f.read()) if username in user_dic and password == user_dic[username]: print('login successful') login_dic['user'] = username login_dic['status'] = True res = func(*args, **kwargs) return res else: print('login error') elif AuthType == "ldap": print("LDAP认证方式") elif AuthType == "MySQL": print("MySQL认证方式") else: print("其他认证方式") return wrapper return auth @Decorator() def Index(): print("Welcome to Index!") @Decorator(AuthType="MySQL") def home(name): print("Welecome %s to home page!"%name) Index() home("程小航") #以上代码执行结果如下: username:rianley password:123 login successful Welcome to Index! MySQL认证方式
四.小试牛刀
1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登陆成功一次,后续的函数都无需再验证。
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :rianley #blog:http://www.cnblogs.com/rianley # user_dic = { # 'rianley':'123', # 'Golang':"666", # 'Python':"888", # } # # with open("user.db","w",encoding="utf-8")as f: # f.write(str(user_dic)) db_path = "user.db" login_dic ={ 'user':None, "status":False, } def auth(func): def wrapper(*args,**kwargs): if login_dic['user'] and login_dic['status']: res = func(*args, **kwargs) return res username = input("username:") password = input("password:") with open(db_path, "r", encoding="utf-8")as f: user_dic = eval(f.read()) if username in user_dic and password == user_dic[username]: print('login successful') login_dic['user'] = username login_dic['status'] = True res = func(*args,**kwargs) return res else: print('login error') return wrapper @auth def Index(): print("Welcome to Index!") @auth def home(name): print("Welecome %s to home page!"%name) Index() home("程小航") 以上代码执行结果如下: username:rianley password:123 login successful Welcome to Index! Welecome 程小航 to home page!
2.编写下载网页内容的函数,要求功能是:用户传入一个URL,函数返回下载页面的内容。
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :rianley #blog:http://www.cnblogs.com/rianley from urllib.request import urlopen import os cache_path=r'cache.txt' def make_cache(func): def wrapper(*args,**kwargs): if os.path.getsize(cache_path):#说明有缓存 print('\033[45m=========有缓存=========\033[0m') with open(cache_path,'rb') as f: res=f.read() else: res=func(*args,**kwargs) #下载 with open(cache_path,'wb') as f: #制作缓存 f.write(res) return res return wrapper @make_cache def get(url): return urlopen(url).read() print('============first============') print(get('http://www.cnblogs.com/rianley')) print('============second===========') print(get('http://www.cnblogs.com/rianley')) print('============third============') print(get('http://www.cnblogs.com/rianley'))
3.装饰器包装原函数案例
#!/usr/bin/env python #_*_coding:utf-8_*_ #@author :rianley #blog:http://www.cnblogs.com/rianley FuncDict={} def MakeDict(key): def deco(func): FuncDict[key]=func # def wrapper(*args,**kwargs): #此行及以下3行可以不写,这样就可以达到隐藏你原来函数的名字。 # res = func(*args,**kwargs) # return res # return wrapper return deco @MakeDict("one") def First(): print("From Shell") @MakeDict("two") def Second(): print("From Second") @MakeDict("three") def Third(): print("From Third") print(FuncDict) while True: cmd = input(">>>:").strip() if cmd in FuncDict: FuncDict[cmd]() #以上代码执行结果如下: {'one': <function First at 0x027E38E8>, 'two': <function Second at 0x027E3810>, 'three': <function Third at 0x027E38A0>} >>>:three From Third >>>:one From Shell >>>:two From Second >>>: >>>: >>>:
心灵鸡汤: 莫让惰性,成为惯性 (不要让懒惰成为习惯!)
欢迎加入 程序员的自我修养 群:687226766