Python?裝飾器常用的創(chuàng)建方式及源碼示例解析
裝飾器簡介
裝飾器(decorator)是一種高級Python語法??梢詫σ粋€函數(shù)、方法或者類進行加工。在Python中,我們有多種方法對函數(shù)和類進行加工,相對于其它方式,裝飾器語法簡單,代碼可讀性高。因此,裝飾器在Python項目中有廣泛的應用。修飾器經(jīng)常被用于有切面需求的場景,較為經(jīng)典的有插入日志、性能測試、事務處理, Web權限校驗, Cache等。
裝飾器的優(yōu)點是能夠抽離出大量函數(shù)中與函數(shù)功能本身無關的雷同代碼并繼續(xù)重用。即,可以將函數(shù)“修飾”為完全不同的行為,可以有效的將業(yè)務邏輯正交分解。概括的講,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能。例如記錄日志,需要對某些函數(shù)進行記錄。笨的辦法,每個函數(shù)加入代碼,如果代碼變了,就悲催了。裝飾器的辦法,定義一個專門日志記錄的裝飾器,對需要的函數(shù)進行裝飾。
基礎通用裝飾器
源碼示例
def wrapper_out(func):
print('-- wrapper_out start --')
def inner(*args, **kwargs):
print("-- inner start --")
ret = func(*args, **kwargs)
print("-- inner end --")
return ret
print('-- wrapper_out end --')
return inner
@wrapper_out
def test():
print("--test--")
return 1 * 2
if __name__ == '__main__':
print(">>>>>>>>>>>>>>")
print(test())執(zhí)行結(jié)果
-- wrapper_out start --
-- wrapper_out end --
>>>>>>>>>>>>>>
-- inner start --
--test--
-- inner end --
2
帶參數(shù)裝飾器
源碼示例
def wrapper_out(mode=None):
print('-- wrapper_out start --')
def inner_1(func):
print("-- inner_1 start --")
def inner_2(*args, **kwargs):
print("-- inner_2 start --")
print(f"mode: {mode}")
ret = func(*args, **kwargs)
print("-- inner_2 end --")
return ret
print("-- inner_2 end --")
return inner_2
print('-- wrapper_out end --')
return inner_1
@wrapper_out(mode=2)
def test():
print("--test--")
return 1 * 2
if __name__ == '__main__':
print(">>>>>>>>>>>>>>")
print(test())源碼結(jié)果
-- wrapper_out start --
-- wrapper_out end --
-- inner_1 start --
-- inner_2 end --
>>>>>>>>>>>>>>
-- inner_2 start --
mode: 2
--test--
-- inner_2 end --
2
源碼解析
帶參數(shù)的裝飾器函數(shù), 需要多嵌套一層, 外層裝飾器的參數(shù)
預加載的時候已經(jīng)是根據(jù)函數(shù)的編寫順序進行加載
執(zhí)行順序在對應的最內(nèi)存函數(shù)中調(diào)用最外層的裝飾器函數(shù)參數(shù)
被裝飾函數(shù)是最為 inner_1 的參數(shù)進行傳入, 被裝飾函數(shù)的參數(shù)是作為 inner_2 的參數(shù)傳入
被裝飾函數(shù)的執(zhí)行位置是在 inner_2 中, 使用inner_1 的參數(shù)變量和 inner_2 的參數(shù)變量共同協(xié)助下進行執(zhí)行
同時還要使用裝飾器函數(shù) wrapper_out 的參數(shù)變量進行額外的操作
多裝飾器執(zhí)行順序
源碼示例
def wrapper_out1(func):
print('-- wrapper_out_1 start --')
def inner1(*args, **kwargs):
print("-- inner_1 start --")
ret = func(*args, **kwargs)
print("-- inner_1 end --")
return ret
print('-- wrapper_out1 end --')
return inner1
def wrapper_out2(func):
print('-- wrapper_out_2 start --')
def inner2(*args, **kwargs):
print("-- inner_2 start --")
print("-- inner_2 end --")
print('-- wrapper_out_2 end --')
return inner2
@wrapper_out2
@wrapper_out1
def test():
print("--test--")
return 1 * 2
if __name__ == '__main__':
print(">>>>>>>>>>>>>>")
print(test())執(zhí)行結(jié)果
-- wrapper_out_1 start --
-- wrapper_out1 end --
-- wrapper_out_2 start --
-- wrapper_out_2 end --
>>>>>>>>>>>>>>
-- inner_2 start --
-- inner_1 start --
--test--
-- inner_1 end --
-- inner_2 end --
2
解析
裝飾器的預加載順序是從上往下, 先將裝飾器函數(shù)寫入內(nèi)存
裝飾器的執(zhí)行順序是以最靠近函數(shù)體的裝飾器開始執(zhí)行(從內(nèi)到外)
類裝飾器
源碼示例
class WrapperOut(object):
def __init__(self, func):
print('start init ~~~~~`')
print('func name is %s ' % func.__name__)
self.__func = func
print('end init ~~~~~`')
def __call__(self, *args, **kwargs):
print('start test')
self.__func()
print('end test')
@WrapperOut
def test():
print('this is test func')
if __name__ == '__main__':
print(">>>>>>>>>>>")
test()執(zhí)行結(jié)果
start init ~~~~~`
func name is test
end init ~~~~~`
>>>>>>>>>>>
start test
this is test func
end test
解析
類裝飾器是利用了類初始化 init 析構(gòu)方法來處理 被裝飾函數(shù)的傳入
以及使用 call 方法來滿足被裝飾函數(shù)的執(zhí)行觸發(fā)
到此這篇關于Python 裝飾器常用的創(chuàng)建方式及解析的文章就介紹到這了,更多相關python裝飾器創(chuàng)建方式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
pycharm激活碼免費分享適用最新pycharm2020.2.3永久激活
免費為大家分享Pycharm激活碼,適用最新版pycharm2020.2.3永久激活,pycharm2018,pycharm2019也可永久激活,可成功激活到2089年2020-11-11
基于spring boot 日志(logback)報錯的解決方式
今天小編就為大家分享一篇基于spring boot 日志(logback)報錯的解決方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02
python基于gevent實現(xiàn)并發(fā)下載器代碼實例
這篇文章主要介紹了python基于gevent實現(xiàn)并發(fā)下載器代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11

