一 什么是裝飾器
器即函數
裝飾即修飾,意指為其他函數添加新功能
裝飾器定義:本質就是函數,功能是為其他函數添加新功能
二 裝飾器需要遵循的原則
1.不修改被裝飾函數的源代碼(開放封閉原則)
2.為被裝飾函數添加新功能后,不修改被修飾函數的調用方式
三 實現裝飾器知識儲備
裝飾器=高階函數+函數嵌套+閉包
四 高階函數
高階函數定義:
1.函數接收的參數是一個函數名
2.函數的返回值是一個函數名
3.滿足上述條件任意一個,都可稱之為高階函數

def foo(): print('我的函數名作為參數傳給高階函數') def gao_jie1(func): print('我就是高階函數1,我接收的參數名是%s' %func) func() def gao_jie2(func): print('我就是高階函數2,我的返回值是%s' %func) return func gao_jie1(foo) gao_jie2(foo)

#高階函數應用1:把函數當做參數傳給高階函數 import time def foo(): print('from the foo') def timmer(func): start_time=time.time() func() stop_time=time.time() print('函數%s 運行時間是%s' %(func,stop_time-start_time)) timmer(foo) #總結:我們確實為函數foo增加了foo運行時間的功能,但是foo原來的執行方式是foo(),現在我們需要調用高階函數timmer(foo),改變了函數的調用方式

#高階函數應用2:把函數名當做參數傳給高階函數,高階函數直接返回函數名 import time def foo(): print('from the foo') def timmer(func): start_time=time.time() return func stop_time=time.time() print('函數%s 運行時間是%s' %(func,stop_time-start_time)) foo=timmer(foo) foo() #總結:我們確實沒有改變foo的調用方式,但是我們也沒有為foo增加任何新功能
高階函數總結
1.函數接收的參數是一個函數名
作用:在不修改函數源代碼的前提下,為函數添加新功能,
不足:會改變函數的調用方式
2.函數的返回值是一個函數名
作用:不修改函數的調用方式
不足:不能添加新功能
五 函數嵌套
1 def father(name): 2 print('from father %s' %name) 3 def son(): 4 print('from son') 5 def grandson(): 6 print('from grandson') 7 grandson() 8 son() 9 10 father('林海峰')
六 閉包
1 ''' 2 閉包:在一個作用域里放入定義變量,相當於打了一個包 3 ''' 4 def father(name): 5 def son(): 6 # name='alex' 7 print('我爸爸是 [%s]' %name) 8 def grandson(): 9 # name='wupeiqi' 10 print('我爺爺是 [%s]' %name) 11 grandson() 12 son() 13 14 father('林海峰')
七 無參裝飾器
無參裝飾器=高級函數+函數嵌套
基本框架
1 #這就是一個實現一個裝飾器最基本的架子 2 def timer(func): 3 def wrapper(): 4 func() 5 return wrapper
加上參數
1 def timer(func): 2 def wrapper(*args,**kwargs): 3 func(*args,**kwargs) 4 return wrapper
加上功能
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 func(*args,**kwargs) 6 stop_time=time.time() 7 print('函數[%s],運行時間是[%s]' %(func,stop_time-start_time)) 8 return wrapper
加上返回值
1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res=func(*args,**kwargs) 6 stop_time=time.time() 7 print('函數[%s],運行時間是[%s]' %(func,stop_time-start_time)) 8 return res 9 return wrapper
使用裝飾器
1 def cal(array): 2 res=0 3 for i in array: 4 res+=i 5 return res 6 7 cal=timer(cal) 8 cal(range(10))
語法糖@
1 @timer #@timer就等同於cal=timer(cal) 2 def cal(array): 3 res=0 4 for i in array: 5 res+=i 6 return res 7 8 cal(range(10))
八 裝飾器應用示例

user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, ] current_user={'username':None,'login':False} def auth_deco(func): def wrapper(*args,**kwargs): if current_user['username'] and current_user['login']: res=func(*args,**kwargs) return res username=input('用戶名: ').strip() passwd=input('密碼: ').strip() for index,user_dic in enumerate(user_list): if username == user_dic['name'] and passwd == user_dic['passwd']: current_user['username']=username current_user['login']=True res=func(*args,**kwargs) return res break else: print('用戶名或者密碼錯誤,重新登錄') return wrapper @auth_deco def index(): print('歡迎來到主頁面') @auth_deco def home(): print('這里是你家') def shopping_car(): print('查看購物車啊親') def order(): print('查看訂單啊親') print(user_list) # index() print(user_list) home()

user_list=[ {'name':'alex','passwd':'123'}, {'name':'linhaifeng','passwd':'123'}, {'name':'wupeiqi','passwd':'123'}, {'name':'yuanhao','passwd':'123'}, ] current_user={'username':None,'login':False} def auth(auth_type='file'): def auth_deco(func): def wrapper(*args,**kwargs): if auth_type == 'file': if current_user['username'] and current_user['login']: res=func(*args,**kwargs) return res username=input('用戶名: ').strip() passwd=input('密碼: ').strip() for index,user_dic in enumerate(user_list): if username == user_dic['name'] and passwd == user_dic['passwd']: current_user['username']=username current_user['login']=True res=func(*args,**kwargs) return res break else: print('用戶名或者密碼錯誤,重新登錄') elif auth_type == 'ldap': print('巴拉巴拉小魔仙') res=func(*args,**kwargs) return res return wrapper return auth_deco #auth(auth_type='file')就是在運行一個函數,然后返回auth_deco,所以@auth(auth_type='file') #就相當於@auth_deco,只不過現在,我們的auth_deco作為一個閉包的應用,外層的包auth給它留了一個auth_type='file'參數 @auth(auth_type='ldap') def index(): print('歡迎來到主頁面') @auth(auth_type='ldap') def home(): print('這里是你家') def shopping_car(): print('查看購物車啊親') def order(): print('查看訂單啊親') # print(user_list) index() # print(user_list) home()
九 超時裝飾器

import sys,threading,time class KThread(threading.Thread): """A subclass of threading.Thread, with a kill() method. Come from: Kill a thread in Python: http://mail.python.org/pipermail/python-list/2004-May/260937.html """ def __init__(self, *args, **kwargs): threading.Thread.__init__(self, *args, **kwargs) self.killed = False def start(self): """Start the thread.""" self.__run_backup = self.run self.run = self.__run # Force the Thread to install our trace. threading.Thread.start(self) def __run(self): """Hacked run function, which installs the trace.""" sys.settrace(self.globaltrace) self.__run_backup() self.run = self.__run_backup def globaltrace(self, frame, why, arg): if why == 'call': return self.localtrace else: return None def localtrace(self, frame, why, arg): if self.killed: if why == 'line': raise SystemExit() return self.localtrace def kill(self): self.killed = True class Timeout(Exception): """function run timeout""" def timeout(seconds): """超時裝飾器,指定超時時間 若被裝飾的方法在指定的時間內未返回,則拋出Timeout異常""" def timeout_decorator(func): """真正的裝飾器""" def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs): result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs)) def _(*args, **kwargs): result = [] new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list 'oldfunc': func, 'result': result, 'oldfunc_args': args, 'oldfunc_kwargs': kwargs } thd = KThread(target=_new_func, args=(), kwargs=new_kwargs) thd.start() thd.join(seconds) alive = thd.isAlive() thd.kill() # kill the child thread if alive: raise Timeout(u'function run too long, timeout %d seconds.' % seconds) else: return result[0] _.__name__ = func.__name__ _.__doc__ = func.__doc__ return _ return timeout_decorator @timeout(5) def method_timeout(seconds, text): print('start', seconds, text) time.sleep(seconds) print('finish', seconds, text) return seconds method_timeout(6,'asdfasdfasdfas')