裝飾器的入門到精通

2022-05-01 14:00:09 字數 3865 閱讀 8608

關於裝飾器,在面試時,經常會被問到這兩個問題:

1

、你都用過裝飾器實現過什麼樣的功能?

2、請手寫乙個可以傳參的裝飾器?

這篇部落格就根據這兩個問題,帶大家系統的學習裝飾器的所有內容.希望對大家有所幫助.

hello,裝飾器

入門: 日誌列印器

入門: 時間計時器

高階: 帶引數的函式裝飾器

高階: 不帶引數的類裝飾器

高階: 帶引數的類裝飾器

使用偏函式與類實現裝飾器

裝飾類的裝飾器

wraps裝飾器的作用

內建裝飾器: property

其他裝飾器: 裝飾器實戰

裝飾器的使用方法很簡單:

1. 先定義乙個裝飾器

2. 再定義你的業務函式或者類

3. 最後把裝飾器加在這個函式上面

舉個小栗子:

def

decorator(func):

return

func()

return

@decorator

deffunction():

print("

hello, decorator

")

實際上,裝飾器並不是編碼必須性,意思就是說,你不使用裝飾器完全可以,它的出現,應該是使我們的**

實現的功能:

1. 在函式執行前,先列印一行日誌,通知要執行函式了

2. 函式執行完後,再列印一行日誌,宣布函式執行完畢.

def

log(func): #裝飾函式,引數 func 是被裝飾的函式

def inner(*args,**kwargs):

print('

start running: {} function

'.format(func.__name__

)) res = func(*args,**kwargs) # 執行主函式

print('

stop running')

return

res

return

inner

@log

defmain():

print('

我是主函式

')

輸出結果:

start running: main function

我是主函式

stop running

時間計時器,顧名思義,就是實現乙個能夠計算函式執行時長的功能.

import

time

deftimer(func):

def inner(*args,**kwargs):

start =time.time()

func(*args,**kwargs) #函式真正執行的地方

print('

執行了 {}s

'.format(time.time()-start)) #計算時長

return

inner

@timer

defmain(sleep_time):

time.sleep(sleep_time)

main(10)

輸出結果:

執行了 10.0073800086975098s

通過上面兩個簡單的入門例項,大家應該能體會到裝飾器的工作原理了.

不過,裝飾器的用法還遠不止如此. 回過頭去看看上面的例子,裝飾器是不能接收引數的。其用法,只能適用於一些簡單的場景。不傳參的裝飾器,只能對被裝飾函式,執行固定邏輯。

裝飾器本身是乙個函式,做為乙個函式,如果不能傳參,那這個函式的功能就會很受限,只能執行固定的邏輯。這意味著,如果裝飾器的邏輯**的執行需要根據不同場景進行調整,若不能傳參的話,我們就要寫兩個裝飾器,這顯然是不合理的。

比如說,我們要迴圈執行某乙個函式,迴圈的次數是隨機指定的.

def

loop(count):

defwrap(func):

def inner(*args,**kwargs):

for i in

range(count):

func(i)

return

inner

return

wrap

@loop(6)

defmain(i):

print('

第 {} 次迴圈

'.format(i+1))

main()

輸出結果:

第 1次迴圈

第 2次迴圈

第 3次迴圈

第 4次迴圈

第 5次迴圈

第 6 次迴圈

以上都是基於函式實現的裝飾器,在閱讀別人**時,還可以時常發現還有基於類實現的裝飾器。

基於類裝飾器的實現,必須實現__call____init__兩個內建函式。

__init__:接收被裝飾函式

__call__:實現裝飾邏輯。

還是以日誌列印這個例子為例.

class

log:

def__init__

(self,func): #接收被裝飾函式

self.func =func

def__call__(self, *args, **kwargs): #實現裝飾邏輯

print('[info]:

{} 正在執行

'.format(self.func.__name__

)) res =self.func(*args,**kwargs)

print('

函式執行完畢')

return

res@log

defmain():

print('

我是主函式')

main()

執行結果:

[info]: main 正在執行

我是主函式

函式執行完畢

上面不帶引數的例子,只能列印 info 級別的日誌,正常情況下,我們還需要列印 debug, warning 等級別的日誌.這就需要給類裝飾器傳入引數,指定日誌級別了.

帶引數和不帶引數的類裝飾器有很大不同:

__init__:不再接收被裝飾函式,而是接收傳入引數。

__call__:接收被裝飾函式,實現裝飾邏輯。

class

logger():

def__init__(self,level='

info

'): #接收引數

self.level =level

def__call__

(self, func): # 接收被裝飾函式,實現裝飾邏輯

def wrap(*args,**kwargs):

print('

[{}]正在執行 {}

'.format(self.level,func.__name__

))

return func(*args,**kwargs)

return

wrap

@logger(level='

warning')

defmain():

print('

我是主函式')

main()

執行結果:

[warning]正在執行 main

我是主函式

*參考: 

Phoenix入門到精通

摘要 此phoenix系列文章將會從phoenix的語法和功能特性 相關工具 實踐經驗以及應用案例多方面從淺入深的闡述。希望對phoenix入門 在做架構設計和技術選型的同學能有一些幫助。phoenix是乙個開源的hbase sql層。它不僅可以使用標準的jdbc api替代hbase client...

GIT入門到精通

git工作流 版本回退 分支管理 標籤管理 遠端倉庫 linux torvalds在 1991 年建立了開源的 linux,從此,linux系統不斷發展,已經成為最大的伺服器系統軟體了。linux雖然建立了linux,但linux的壯大是靠全世界熱心的志願者參與的,這麼多人在世界各地為linux編寫...

Git 入門到精通

git是乙個開源的分布式版本控制系統,用以有效 高速的處理從很小到非常大的專案版本管理。git的特點 git 是用於 linux核心開發的版本控制工具。與常用的版本控制工具 cvs,subversion 等不同,它採用了分布式版本庫的方式,不必伺服器端軟體支援 wingeddevil注 這得分是用什...