Python裝飾器
1、簡(jiǎn)介
本質(zhì):
Python的裝飾器就是一個(gè)閉包。
目的:
簡(jiǎn)化代碼操作
2、使用裝飾器的原則:不改變被裝飾函數(shù)的屬性等性質(zhì)
-
使用中間人
g對(duì)象
幫助傳遞參數(shù) -
使用內(nèi)層裝飾器
@functools.wraps(view_func)
回復(fù)被裝飾函數(shù)的屬性等性質(zhì)(舉例2)
3、 舉例1 :定義驗(yàn)證登錄狀態(tài)的裝飾器
# 使用中間人g對(duì)象作為裝飾器和被裝飾函數(shù)中的參數(shù)傳遞者
from
flask
import
session
,
jsonify
,
g
from
myihome
.
utils
.
response_code
import
RET
import
functools
# python的內(nèi)置模塊,存放函數(shù)工具
# 閉包:外層函數(shù)一般就是定義為被裝飾的函數(shù)(view_func(例如這里是:set_user_avatar))"的@外層函數(shù)"
def
login_required
(
view_func
)
:
# 內(nèi)層函數(shù)一般定義為wrapper,并且由于傳遞的參數(shù)不確定,使用*args, **kwargs待定
# @functools.wraps(view_func)這個(gè)函數(shù)裝飾器專(zhuān)門(mén)是用來(lái)裝飾內(nèi)層函數(shù)的,
# 1參數(shù):外層函數(shù)接受的參數(shù),直接傳給里面的就可以了,
# 2意義:內(nèi)層裝飾器加上之后會(huì)改變一些特性:functools的wraps會(huì)將wrapper相關(guān)的屬性和名字恢復(fù)為view_func的屬性和名字,參考博客的例子2
@functools
.
wraps
(
view_func
)
# 在寫(xiě)裝飾器的時(shí)候需要習(xí)慣將這個(gè)內(nèi)層裝飾器補(bǔ)上,避免改變被裝飾函數(shù)的特性
def
wrapper
(
*
args
,
**
kwargs
)
:
# 判斷用戶的登錄狀態(tài)
user_id
=
session
.
get
(
"user_id"
)
# 如果用戶是登錄的,執(zhí)行視圖函數(shù)
if
user_id
is
not
None
:
# g對(duì)象的應(yīng)用,保存user_id,讓其作為參數(shù)傳遞對(duì)象,在視圖函數(shù)中可以通過(guò)g對(duì)象獲取保存數(shù)據(jù)
g
.
user_id
=
user_id
return
view_func
(
*
args
,
**
kwargs
)
else
:
# 如果未登錄,返回未登錄的信息
return
jsonify
(
errno
=
RET
.
SESSIONERR
,
errmsg
=
"用戶未登錄"
)
return
wrapper
# 使用中間人g對(duì)象作為裝飾器和被裝飾函數(shù)中的參數(shù)傳遞者,g對(duì)象就是提供來(lái)保存數(shù)據(jù)的
# 在一次請(qǐng)求之中如果涉及到多個(gè)函數(shù)請(qǐng)求參數(shù)的時(shí)候就可以使用g對(duì)象來(lái)傳參數(shù)
@login_required
def
set_user_avatar
(
)
:
# 本來(lái)是可以直接操作session獲取user_id的,
# 但是使用的裝飾器里面已經(jīng)獲取到了user_id,由裝飾器的原則,不可能變成 def set_user_avatar(user_id):的,所以可以使用中間人g對(duì)象傳遞過(guò)來(lái),不必重復(fù)操作一遍
# user_id = session.get("user_id")
user_id
=
g
.
user_id
pass
# set_user_avatar() 的執(zhí)行就是執(zhí)行wrapper-> wrapper() 直接傳遞參數(shù)到wrapper()里面
4、
舉例2:
內(nèi)層裝飾器
@functools.wraps(func)
的作用
①首先:未加上裝飾器:
def
login_required
(
func
)
:
def
wrapper
(
*
args
,
**
kwargs
)
:
pass
return
wrapper
def
test
(
)
:
"""test python"""
pass
print
(
test
.
__name__
)
print
(
test
.
__doc__
)
Python中萬(wàn)物皆對(duì)象,直接打印出函數(shù)test()的名字和說(shuō)明文檔:
test
test python
②加上裝飾器:
def
login_required
(
func
)
:
def
wrapper
(
*
args
,
**
kwargs
)
:
pass
return
wrapper
@login_required
def
test
(
)
:
"""test python"""
pass
# test -> wrapper :執(zhí)行test(), 實(shí)質(zhì)是執(zhí)行wrapper()
print
(
test
.
__name__
)
# wrapper.__name__
print
(
test
.
__doc__
)
# wrapper.__doc__
打印的結(jié)果為:
wrapper
None
可見(jiàn)已經(jīng)改變test()的屬性了,違反了裝飾器的原則。
③加上內(nèi)層函數(shù)裝飾器:
import
functools
def
login_required
(
func
)
:
@functools
.
wraps
(
func
)
def
wrapper
(
*
args
,
**
kwargs
)
:
pass
return
wrapper
@login_required
def
test
(
)
:
"""test python"""
pass
# test -> wrapper
print
(
test
.
__name__
)
# wrapper.__name__
print
(
test
.
__doc__
)
# wrapper.__doc__
打印結(jié)果為:
test
test python
可見(jiàn)被裝飾函數(shù)的屬性被恢復(fù)了。
參考代碼及項(xiàng)目URL:
https://github.com/too-hoo/myiHome/blob/master/myihome/utils/commons.py
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
