裝飾器是做什麼的呢,簡單的說裝飾器可以為函式新增功能卻不改變函式本身任何原始碼。說到這裡你可能還是對裝飾器的功能不是很懂,那麼思考下面乙個問題。 怎麼在不改變原始碼的情況下實現plus 對x+2呢?
def
plus
(x):
return x+
1if __name__ ==
"__main__"
:#不改變原始碼的情況下實現 讓plus返回x+2
print
(plus(1)
)
單層裝飾
單層有參函式的簡易裝飾
對於python這麼好用的語言,答案肯定是有的,先來看下面一段**吧。
def
add_func
(func)
:def
inner
(x):
#裝飾函式
a = func(x)
return a+
1return inner
@add_func
defplus
(x):
return x+
1if __name__ ==
"__main__"
:#不改變原始碼和呼叫關係的情況下實現 讓plus做到x+2
print
(plus(1)
)
接下來就讓我們分析一下上面的**吧:
首先對於@add_func這個符號怎麼去理解呢,首先@是乙個修飾符,修飾符怎麼去理解呢,修飾符@後面的函式去呼叫下面被修飾的函式。
所以修飾符的大概功能是plus = add_func(plus)。我們如果把上面**中的@去掉,然後用下面兩行**在main中實現也是可以實現答案的
plus = add_func(plus)
print
(plus(1)
)
具體的原理就是python對於任何變數的名字返回的都是位址,對於位址是函式的變數來說,在變數的末尾加上(),就可以實現函式的功能了。所以在add_func(plus)的意思就是把plus函式的位址放到add_func的引數中去,這樣返回出來的值就是inner , 對於inner來說 他是inner函式的位址,這個函式實現了對plus返回值加1就是把x加1的功能,所以我們把inner函式的位址又賦值給了plus這個變數。這樣一來,plus()實際上是執行了add_func.inner()這個函式。
單層無參函式的簡易裝飾
這一功能最常見的用處是用來驗證所執行的許可權。原理已經在上面具體闡述過了,所以我們就實現簡單的demo來知道處理的機制就可以了。
def
add_func
(func)
:def
wrap()
:print
("在這個位置實現登入的許可權驗證"
) func(
)print
("在這裡可以處理登入完成後的事項"
)return wrap
@add_func
deflogin()
:print
("登入成功"
)if __name__ ==
"__main__"
:#不改變原始碼和呼叫關係的情況下實現 讓login可以驗證登入
login(
)
多適應裝飾器
現在我們的需求在登入的基礎上改變,因為我們的**效益高,我們開通了vip渠道,來為vip提供更加優質的服務,並且服務會根據vip的等級不同而有區分。所以我們需要實現兩個函式 login() vip_login(vip_level),之前的login我們已經實現好了,難道我們又為vip_login單獨寫乙個裝飾器在裝飾函式上加上變數嗎。先看下面**.
def
add_func
(func)
:def
wrap
(*args,
**kwargs)
:print
("在這個位置實現登入的許可權驗證"
) func(
*args,
**kwargs)
print
("在這裡可以處理登入完成後的事項"
)return wrap
@add_func
deflogin()
:print
("登入成功"
)@add_func
defvip_login
(vip_level)
:print
("vip登入成功,您的當前等級"
+str
(vip_level)
)if __name__ ==
"__main__"
:#login()
vip_login(
1)
答案非常簡單,我們在裝飾函式的引數列表中加入萬能的適應引數就可以解決了,有不懂的小夥伴可以自己去查閱一下資料,這裡不做解釋了。
這樣一來,我們的乙個裝飾器可以對許許多多的函式增加功能還不破壞他們的原始碼。
多層裝飾器
如果會用單層裝飾器,其實已經可以解決大多數情況了,那如果我們要好好理解一下裝飾器的詳細原理的話就可以通過乙個雙層的裝飾器來進行研究。
def
yu_lang_long
(fun)
:#2 裝飾 makeitalic.inner()
print
('----獄狼龍裝飾階段----'
)def
inner()
:print
('----獄狼龍執行階段----'
)return
'《獄狼龍》'
+ fun()+
'return inner #3 test 被裝飾成 makebold.inner() 注意此時的test
deflei_lang_long
(fun)
:print
('----雷狼龍裝飾階段----'
)def
inner()
:print
('----雷狼龍執行階段----'
)return
'《雷狼龍》'
+ fun()+
'return inner # 1
@yu_lang_long
@lei_lang_long
defshou_lie()
:print
('----狩獵執行階段----'
)return
'狩獵完成'
print
(shou_lie(
))
輸出:
----雷狼龍裝飾階段----
----獄狼龍裝飾階段----
----獄狼龍執行階段----
----雷狼龍執行階段----
----狩獵執行階段----
《獄狼龍》《雷狼龍》狩獵完成裝飾時機 通過上面裝飾時機的介紹,我們可以知道,在執行到@yu_lang_long的時候,需要對下面的函式進行裝飾,此時直譯器繼續往下走,發現並不是乙個函式名,而是乙個裝飾器,這時候,@yu_lang_long裝飾器暫停執行,而接著執行接下來的裝飾器@lei_lang_long,這時候直譯器發現下面是乙個函式,所以就把shou_lie這個函式位址傳遞給lei_lang_long,所以就輸出了雷狼龍裝飾階段,經過裝飾的函式這下可以被直譯器識別了,所以繼續進行獄狼龍的裝飾。裝飾完成後,就應該執行shou_lie()這個函式了。
執行步驟 我們再把思路捋一遍,狩獵函式先被雷狼龍裝飾,裝飾完成後被獄狼龍裝飾,然後開始執行。所以現在執行的就是獄狼龍的裝飾函式,所以列印出獄狼龍執行階段,下面的fun 實際上是被 雷狼龍裝飾的狩獵函式,所以列印出來的雷狼龍執行階段,雷狼龍裝飾函式裡面的fun就是實際的狩獵函式了所以列印出來的就是狩獵執行階段。
回溯步驟 執行完了,就要從底層函式一層一層回溯當上層,先是狩獵階段,然後是雷狼龍,然後是獄狼龍。至此裝飾函式執行完畢。
python裝飾器 函式裝飾器,類裝飾器
只要實現此 模式,這個obj就叫乙個裝飾器 參考 函式裝飾器 例子 def decorator func def inner args,kwargs print before.res func args,kwargs print after.return res return inner decor...
python 裝飾器 函式裝飾器 類裝飾器
python函式裝飾器和類裝飾器筆記.usr bin env python coding utf 8 author ivan file decorators.py version from functools import wraps 裝飾器 目的是為了給函式新增附加功能 1.不帶引數裝飾器 此方式...
python裝飾器 裝飾器工廠函式
使用裝飾器實現如下所示的列印 小白聯盟def printequel func1 def inner1 print 15 func1 return inner1 def printstar func2 def inner2 print 15 func2 return inner2 printequel...