函式裝飾器的工作原理是怎樣的呢?假設用 funa() 函式裝飾器去裝飾 funb() 函式,如下所示:
#funa 作為裝飾器函式
deffuna
(fn)
:#...
fn()# 執行傳入的fn引數
#...
return
'...'
@funa
deffunb()
:#...
實際上,上面程式完全等價於下面的程式:
def
funa
(fn)
:#...
fn()# 執行傳入的fn引數
#...
return
'...'
deffunb()
:#...
funb = funa(funb)
將 b 作為引數傳給 a() 函式;
將 a() 函式執行完成的返回值反饋回 b。
舉個例項:
#funa 作為裝飾器函式
deffuna
(fn)
:print
("c語言中文網"
) fn(
)# 執行傳入的fn引數
print
("")return
"裝飾器函式的返回值"
@funa
deffunb()
:print
("學習 python"
)
程式執行流程為:
c語言中文網
學習 python
在此基礎上,如果在程式末尾新增如下語句:
print
(funb)
其輸出結果為:
裝飾器函式的返回值
顯然,被「@函式」修飾的函式不再是原來的函式,而是被替換成乙個新的東西(取決於裝飾器的返回值),即如果裝飾器函式的返回值為普通變數,那麼被修飾的函式名就變成了變數名;同樣,如果裝飾器返回的是乙個函式的名稱,怎麼被修飾的函式名依然表示乙個函式。
實際上,所謂函式裝飾器,就是通過裝飾器函式,在不修改原函式的前提下,來對函式的功能進行合理的擴充。在分析 funa() 函式裝飾器和 funb() 函式的關係時,細心的讀者可能會發現乙個問題,即當 funb() 函式無引數時,可以直接將 funb 作為 funa() 的引數傳入。但是,如果被修飾的函式本身帶有引數,那應該如何傳值呢?
比較簡單的解決方法就是在函式裝飾器中巢狀乙個函式,該函式帶有的引數個數和被裝飾器修飾的函式相同。例如:
def
funa
(fn)
:# 定義乙個巢狀函式
defsay
(arc)
:print
("python教程:"
,arc)
return say
@funa
deffunb
(arc)
:print
("funb():"
, a)
funb(
"/python"
)程式執行結果為:
python教程: http:
/python
這裡有必要給讀者分析一下這個程式,其實,它和如下程式是等價的:
def
funa
(fn)
:# 定義乙個巢狀函式
defsay
(arc)
:print
("python教程:"
,arc)
return say
deffunb
(arc)
:print
("funb():"
, a)
funb = funa(funb)
funb(
"/python"
)
如果執行此程式會發現,它的輸出結果和上面程式相同。
顯然,通過 funb() 函式被裝飾器 funa() 修飾,funb 就被賦值為 say。這意味著,雖然我們在程式顯式呼叫的是 funb() 函式,但其實執行的是裝飾器巢狀的 say() 函式。
但還有乙個問題需要解決,即如果當前程式中,有多個(≥ 2)函式被同乙個裝飾器函式修飾,這些函式帶有的引數個數並不相等,怎麼辦呢?
最簡單的解決方式是用 *args 和 **kwargs 作為裝飾器內部巢狀函式的引數,*args 和 **kwargs 表示接受任意數量和型別的引數。舉個例子:
def
funa
(fn)
:# 定義乙個巢狀函式
defsay
(*args,
**kwargs)
: fn(
*args,
**kwargs)
return say
@funa
deffunb
(arc)
:print
("c語言中文網:"
,arc)
@funa
defother_funb
(name,arc)
:print
(name,arc)
funb(
"")other_funb(
"python教程:"
,"/python"
)執行結果為:
c語言中文網: http:
python教程: http:
/python
上面示例中,都是使用乙個裝飾器的情況,但實際上,python 也支援多個裝飾器,比如:
@funa
@funb
@func
deffun()
:#...
上面程式的執行順序是裡到外,所以它等效於下面這行**:
fun = funa( funb ( func (fun)
))
比如**很多頁面需要登入後才能操作,這裡就可以把這個登入判斷寫成乙個裝飾器函式;
需要登入才能操作的頁面直接呼叫上面寫的函式 @裝飾器函式,把當前頁作為乙個引數傳過去;
裝飾器函式接收到頁面後,判斷當前使用者是否登入,如果登入則返回2步真正的頁面,否則跳轉到登入頁面;
例項參考:《django(十六)基於模板的登入案例》
def
login_required
(view_func)
:'''登入判斷裝飾器'''
def(request,
*view_args,
**view_kwargs)
:# 判斷使用者是否登入
if request.session.has_key(
'islogin'):
# 使用者已登入,呼叫對應的檢視
return view_func(request,
*view_args,
**view_kwargs)
else
:# 使用者未登入,跳轉到登入頁
return redirect(
'/login'
)
呼叫:
# /change_pwd
@login_required #作用:把此頁面作為乙個引數傳到login_required裡
defchange_pwd
(request)
:'''顯示修改密碼頁面'''
return render(request,
'booktest/change_pwd.html'
)
Python學習筆記 函式裝飾器及用法
函式裝飾器 當程式使用 函式 比如函式a 裝飾另乙個函式 比如函式b 時,實際上完成如下兩步 將被修飾的函式 函式b 作為引數傳給 符號引用的函式 函式a 將函式b替換 裝飾 成第1步的返回值 事例def funa fn print a fn 執行傳入的fn引數 return fkit 下面裝飾效果...
python函式裝飾器的用法
一 什麼是裝飾器 用來給其他固定函式增加其他功能的一種函式。裝飾器的實現是函式裡面巢狀函式,讓其他函式在不需要做任何 改動的前提下增加額外功能。裝飾器需要傳遞乙個函式,返回值也是乙個函式物件 二 裝飾器的應用舉例 1.需求 使用者登陸驗證的裝飾器,如果使用者登陸成功,則執行被裝飾的函式,如果登陸失敗...
python函式裝飾器 的用法
是python中的乙個語法糖,decorator表示宣告乙個函式裝飾器,這條宣告語句中,decorator通過 被宣告為了函式裝飾器,其作用是對緊接著定義的函式進行進一步的裝飾,並返回與被裝飾函式同名的函式。decorator用法規則 1 裝飾器函式decorator需要先定義 2 當要裝飾乙個函式...