import time
'''
我們先來看一個(gè)類裝飾器的案例
Python中一切都是對(duì)象,函數(shù)也是對(duì)象(是個(gè)具有特殊__call__方法的對(duì)象),執(zhí)行 對(duì)象(*args,**kwargs) 相當(dāng)于執(zhí)行對(duì)象的 __call__(self,*args,**kargs) 方法
'''
class ProfilingDecorator:
def __init__(self,func):
self.func=func
def __call__(self,*args,**kwargs):
start_time=time.time()
result=self.func(*args,**kwargs)
end_time=time.time()
print('[Time elapsed for args={}]:{}'.format(args,end_time-start_time))
return result
@ProfilingDecorator #相當(dāng)于 fib=ProfilingDecorator(fib),我們執(zhí)行fib(*args,**kwarg)相當(dāng)于執(zhí)行fib對(duì)象的__call__方法
def fib(n):
if n<2:
return 1
current,current_prev=1,1
for _ in range(2,n):
current,current_prev=current+current_prev,current
return current
def main_01():
n=77
print('[Fib for n={}]:{}'.format(n,fib(n)))
print('-'*100)
n=100
print('[Fib.__call__ for n={}]:{}'.format(n,fib.__call__(n)))
"""
執(zhí)行main_01的輸出結(jié)果是:
[Time elapsed for args=(77,)]:1.0728836059570312e-05
[Fib for n=77]:5527939700884757
----------------------------------------------------------------------------------------------------
[Time elapsed for args=(100,)]:8.58306884765625e-06
[Fib.__call__ for n=100]:354224848179261915075
"""
'''
我們看多個(gè)裝飾器裝飾同一函數(shù)的使用案例
下面我們通過裝飾器類來統(tǒng)計(jì)原始函數(shù)運(yùn)行時(shí)間,并且將原始函數(shù)的輸出結(jié)果
'''
#這個(gè)裝飾器統(tǒng)計(jì)運(yùn)行時(shí)長
class ProfillingDecorator:
def __init__(self,func):
print(">>>>>>>>>>>>>>Inside ProfillingDecorator.__init_")
self.func=func
def __call__(self,*args):
print(">>>>>>>>>>>>>>Inside ProfillingDecorator.__call__")
start_time=time.time()
result=self.func(*args)
end_time=time.time()
print('[Time elapsed for args={}]:{}'.format(args,end_time-start_time))
return result
#這個(gè)裝飾器將輸出結(jié)果轉(zhuǎn)轉(zhuǎn)變?yōu)镠TML格式
class ToHTMLDecorator:
def __init__(self,func):
print(">>>>>>>>>>>>>>Inside ToHTMLDecorator.__init__")
self.func=func
def __call__(self,*args,**kwargs):
print(">>>>>>>>>>>>>>Inside ToHTMLDecorator.__call__")
return "<html><body>{}</body></html>".format(self.func(*args,**kwargs))
@ToHTMLDecorator
@ProfillingDecorator
def fib(n):
print(">>>>>>>>>>>>>>Inside fib")
if n<2:
return 1
current_prev,current=1,1
for _ in range(2,n):
current,current_prev=current_prev+current,current
return current
def main_02():
n=77
print('[Fib for n={}]:{}'.format(n,fib(n)))
print('-'*100)
n=100
print('[Fib.__call__ for n={}]:{}'.format(n,fib.__call__(n)))
'''
main_02執(zhí)行后輸出結(jié)果如下:
我們結(jié)合輸出來分析一波
>>>>>>>>>>>>>>Inside ProfillingDecorator.__init_
>>>>>>>>>>>>>>Inside ToHTMLDecorator.__init__
出現(xiàn)這個(gè)輸出的原因很簡單, 結(jié)合我們裝飾器初始化的代碼,相當(dāng)于先執(zhí)行fib_mid=ProfillingDecorator(fib)然后執(zhí)行fib=ToHTMLDecorator(fib_mid)
>>>>>>>>>>>>>>Inside ToHTMLDecorator.__call__ --------------------|結(jié)合初始化代碼,經(jīng)過兩個(gè)裝飾器初始化后對(duì)象其實(shí)是個(gè)ToHTMLDecorator對(duì)象,所以最先執(zhí)行的___call___方法也就是ToHTMLDecorator的__call__方法
>>>>>>>>>>>>>>Inside ProfillingDecorator.__call__ -------------------|--------|ToHTMLDecorator的func其實(shí)是ProfillingDecorator對(duì)象,所以我們執(zhí)行當(dāng)前func的__call__方法其實(shí)是執(zhí)行ProfillingDecorator的__call__方法
>>>>>>>>>>>>>>Inside fib --------------------------------------------|--------|------ProfillingDecorator執(zhí)行當(dāng)前func的__call__方法,ProfillingDecorator的func是fib對(duì)象,我們?cè)谶@里要執(zhí)行是fib的__call__方法
[Time elapsed for args=(77,)]:1.049041748046875e-05------------------|--------|
[Fib for n=77]:<html><body>5527939700884757</body></html> -----------|
----------------------------------------------------------------------------------------------------
下面我們就不解釋了,和上面一樣
>>>>>>>>>>>>>>Inside ToHTMLDecorator.__call__
>>>>>>>>>>>>>>Inside ProfillingDecorator.__call__
>>>>>>>>>>>>>>Inside fib
[Time elapsed for args=(100,)]:7.3909759521484375e-06
[Fib.__call__ for n=100]:<html><body>354224848179261915075</body></html>
'''
"""
其實(shí)Python裝飾器除了通過類來實(shí)現(xiàn),還可以通過函數(shù)來實(shí)現(xiàn)
下面來看一個(gè)案例
"""
def profilling_decorator(func):
print('>>>>>>Inside profilling_decorator')
def wrapped_func(*args,**kwargs):
print('>>>>>>Inside profilling_decorator.wrapped_func')
start_time=time.time()
result=func(*args,**kwargs)
end_time=time.time()
print('[Time alsped for n={}]:{}'.format(args,end_time-start_time))
return result
return wrapped_func
@profilling_decorator
def fib(n):
print('>>>>>>Inside fib')
if n<2:
return 1
current_prev,current=1,1
for _ in range(2,n):
current_prev,current=current,current_prev+current
return current
def main_03():
n=77
print("Fibonacci number for n={}:{}".format(n,fib(n)))
'''
main_03執(zhí)行后輸出結(jié)果如下:
>>>>>>Inside profilling_decorator
>>>>>>Inside profilling_decorator.wrapped_func
>>>>>>Inside fib
[Time alsped for n=(77,)]:1.0967254638671875e-05
Fibonacci number for n=77:5527939700884757
'''
"""
使用函數(shù)裝飾器的時(shí)候,必須返回一個(gè)函數(shù)供用戶使用,此處返回的是wrapped_func函數(shù),這個(gè)函數(shù)中使用了func這個(gè)對(duì)象,這種就是閉包,
即使profilling_decorator執(zhí)行完畢,profilling_decorator的傳入?yún)?shù)func也會(huì)在wrapped_func中保存
"""
'''
但是裝飾器會(huì)有些副作用,由于返回的函數(shù)不是原函數(shù),所以會(huì)失去原函數(shù)的__main__與__doc__等屬性
比如以下這個(gè)例子
'''
def dummy_decorator(f):
print('Inside dummy_decorator')
def wrap_f():
print('Inside wrap_f')
return f()
return wrap_f
@dummy_decorator
def do_nothing():
print('Inside do_nothing')
def main_04():
print("\nWrapped Function:",do_nothing.__name__,"\n")
do_nothing()
'''
運(yùn)行main_04,執(zhí)行結(jié)果如下:
Inside dummy_decorator
Wrapped Function: wrap_f
可見相關(guān)重要屬性已被更改
Inside wrap_f
Inside do_nothing
'''
'''
避免者中情況的發(fā)生有兩種做法
第一種:直接將返回函數(shù)__name__,__doc__等重要屬性設(shè)置為傳入?yún)?shù)func的
'''
def dummy_decorator(f):
print('Inside dummy_decorator')
def wrap_f():
print('Inside wrap_f')
return f()
wrap_f.__name__=f.__name__
wrap_f.__doc__=f.__doc__
return wrap_f
@dummy_decorator
def do_nothing():
print('Inside do_nothing')
def main_05():
print("\nWrapped Function:",do_nothing.__name__,"\n")
do_nothing()
'''
輸出結(jié)果為:
Inside dummy_decorator
Wrapped Function: do_nothing
Inside wrap_f
Inside do_nothing
'''
'''
第二種:直接使用Python標(biāo)準(zhǔn)庫提供的模塊,保留重要參數(shù)
'''
from functools import wraps
def dummy_decorator(f):
print('Inside dummy_decorator')
@wraps(f)
def wrap_f():
print('Inside wrap_f')
return f()
return wrap_f
@dummy_decorator
def do_nothing():
print('Inside do_nothing')
def main_06():
print("\nWrapped Function:",do_nothing.__name__,"\n")
do_nothing()
'''
輸出結(jié)果為:
Inside dummy_decorator
Wrapped Function: wrap_f
Inside wrap_f
Inside do_nothing
'''
"""
現(xiàn)在我們有了一個(gè)新需求,需要耗時(shí)統(tǒng)計(jì)裝飾器按照我們的設(shè)置,以秒或者毫秒為單位顯示返回運(yùn)行耗時(shí)
這個(gè)時(shí)候我們就需要向裝飾傳入時(shí)間單位參數(shù)unit,者也是一個(gè)閉包,傳入的時(shí)間單位unit參數(shù)被wrap_f保存著
"""
def profilling_decorator_with_unit(unit):
def profiling_decorator(f):
@wraps(f)
def wrap_f(*args,**kwargs):
start_time=time.time()
result=f(*args,**kwargs)
end_time=time.time()
if unit=='seconds':
elapsed_time=(end_time-start_time)/1000
else:
elapsed_time=(end_time-start_time)
print('[Time elapsed for args={}]:{}'.format(args,elapsed_time))
return result
return wrap_f
return profiling_decorator
@profilling_decorator_with_unit('seconds')
@profilling_decorator_with_unit('other')
def fib(n):
if n<2:
return 1
current,current_prev=1,1
for _ in range(2,n):
current_prev,current=current,current+current_prev
return current
def main_07():
n=77
print("Fibonacci number for n={}:{}".format(n,fib(n)))
print('fib_function_name:{}'.format(fib.__name__))
'''
執(zhí)行main_07時(shí)分三種情況:
情況1
@profilling_decorator_with_unit('second')
def fib(n):
輸出為:
[Time elapsed for args=(77,)]:1.0967254638671875e-08 #按照秒輸出
Fibonacci number for n=77:5527939700884757
fib_function_name:fib
情況2
@profilling_decorator_with_unit('other')
def fib(n):
輸出為:
[Time elapsed for args=(77,)]:1.2159347534179688e-05 #按照毫秒輸出
Fibonacci number for n=77:5527939700884757
fib_function_name:fib
情況3
@profilling_decorator_with_unit('seconds')
@profilling_decorator_with_unit('other')
def fib(n):
輸出為:
[Time elapsed for args=(77,)]:1.0013580322265625e-05 #按照毫秒輸出
[Time elapsed for args=(77,)]:4.720687866210938e-08 #按照秒輸出
Fibonacci number for n=77:5527939700884757
fib_function_name:fib
其實(shí)者個(gè)很好理解,我們先得到profilling_decorator_with_unit()執(zhí)行的結(jié)果profiling_decorator,然后我們將fib函數(shù)傳入profiling_decorator_with_unit
'''
04裝飾器模式
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 橋接模式 要實(shí)現(xiàn)多個(gè)有相同的類的操作,他們又有各自的控制單元,如車控鑰匙控制車輛的上鎖、解鎖。如果每種鑰匙都對(duì)應(yīng)每...
- http://blog.csdn.net/hp910315/article/details/51111744 代理...
- 工作需要使用學(xué)習(xí)Python, 發(fā)現(xiàn)Python裝飾器很神奇,所以把以前做游戲用到的c#的裝飾器模式撿起來對(duì)比了下...
- 適配器與裝飾器模式的別名都是包裝模式(Wrapper)。 區(qū)別 適配器模式的意義 將一個(gè)接口轉(zhuǎn)變成另一個(gè)接口,目的...