裝飾器
一 什麼是裝飾器
器即函數
裝飾即修飾,意指爲其他函數添加新功能
裝飾器定義:本質就是函數,功能是爲其他函數添加新功能
二 裝飾器需要遵循的原則
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.函數的返回值是一個函數名
作用:不修改函數的調用方式
不足:不能添加新功能
五 函數嵌套
def father(name):
print('from father %s' %name)
def son():
print('from son')
def grandson():
print('from grandson')
grandson()
son()
father('father')
六 閉包
'''
閉包:在一個作用域裏放入定義變量,相當於打了一個包
'''
def father(name):
def son():
# name='alex'
print('我爸爸是 [%s]' %name)
def grandson():
# name='wupeiqi'
print('我爺爺是 [%s]' %name)
grandson()
son()
father('林海峯')
七 無參裝飾器
無參裝飾器=高級函數+函數嵌套
基本框架
#這就是一個實現一個裝飾器最基本的架子
def timer(func):
def wrapper():
func()
return wrapper
加上參數
def timer(func):
def wrapper(*args,**kwargs):
func(*args,**kwargs)
return wrapper
加上功能
import time
def timer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs)
stop_time=time.time()
print('函數[%s],運行時間是[%s]' %(func,stop_time-start_time))
return wrapper
加上返回值
import time
def timer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('函數[%s],運行時間是[%s]' %(func,stop_time-start_time))
return res
return wrapper
使用裝飾器
def cal(array):
res=0
for i in array:
res+=i
return res
cal=timer(cal)
cal(range(10))
語法糖@
@timer #@timer就等同於cal=timer(cal)
def cal(array):
res=0
for i in array:
res+=i
return res
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')