Python---裝飾器詳解

定義:

本質(zhì)上是一個(gè)函數(shù)自脯。作用是用來(lái)裝飾另一個(gè)函數(shù)(即被裝飾函數(shù))剩檀,給被裝飾函數(shù)添加功能澄干。前提是不能改變被裝飾函數(shù)的源代碼和調(diào)用方式慧库。這樣的一個(gè)函數(shù)稱(chēng)之為裝飾器跷跪。

解析:

下面我們?cè)挷欢嗾f(shuō),直接用代碼說(shuō)明齐板。下面是一個(gè)函數(shù)吵瞻。

1 def add():
2     b=1+2
3     print(b)
4
5 add()
程序輸出:
————————

3

————————
  • 現(xiàn)在我要給這個(gè)函數(shù)增加一個(gè)解釋性的句子,如下甘磨,我們可以編寫(xiě)一個(gè)裝飾器:
#原函數(shù)
def add():
    a=1+2
    print(a)  
#裝飾器
def decorator(func):
    def warpper():
        print("1+2的結(jié)果是:")
        func()
    return warpper
#注意此句   
add=decorator(add)
#調(diào)用函數(shù)
add()

程序輸出:

——————————

1+2的結(jié)果是:

3

——————————
  • 這樣我們就成功的達(dá)成了我們的目的橡羞。這里要注意第12行的這一句,這一句是將add這個(gè)函數(shù)對(duì)象傳入了decorator()函數(shù)济舆,返回的是一個(gè)新函數(shù)變量卿泽,這個(gè)新函數(shù)對(duì)象又重新賦值給add,這樣就可以保證不改變被裝飾函數(shù)的調(diào)用方式不變滋觉。在Python語(yǔ)法中有一種更優(yōu)雅的方式可以代替第十二行的語(yǔ)句签夭。如下:
#裝飾器
def decorator(func):
    def warpper():
        print("1+2的結(jié)果是:")
        func()
    return warpper

#add=decorator(add)
#原函數(shù)
@decorator#換成@符號(hào)
def add():
    a=1+2
    print(a)
#調(diào)用函數(shù)
add()

在被裝飾函數(shù)前面直接加上“@xxx”(xxx為裝飾器函數(shù)名)即可

被裝飾函數(shù)有參數(shù)怎么辦?

  • 如果被裝飾器函數(shù)有參數(shù)呢椎侠?該怎們班第租?不用擔(dān)心,我們可以用不定參數(shù)的形式來(lái)收集參數(shù)我纪。實(shí)例代碼如下:
def decorator(func):
    def warpper(*args,**kwargs):
        print("相加的結(jié)果是:")
        func(*args,**kwargs)
    return warpper

@decorator
def add(x,y):
    a=x+y
    print(a)

add(2,3)

程序輸出:

——————————————————
相加的結(jié)果是:
5
——————————————————

如上慎宾,我們給包裝函數(shù)加上接收參數(shù),然后傳給func()函數(shù)就行了宣羊。這樣不管被裝飾函數(shù)有怎樣的參數(shù)都不怕了璧诵。

下面寫(xiě)一個(gè)頁(yè)面驗(yàn)證的裝飾器。

  • 大家知道有些網(wǎng)站的一部分頁(yè)面是要求用戶登錄之后才可以訪問(wèn)的仇冯,比如下面的三個(gè)函數(shù)(分別代表三個(gè)頁(yè)面):
def index():
    print("welcome to the index page")
def home():
    print("welcome to the home page")
def bbs():
    print("welcome to the bbs page")
    return "I am the return contents"
  • 假如說(shuō)現(xiàn)在我們要給home頁(yè)面和bbs頁(yè)面加上驗(yàn)證之宿,顯然現(xiàn)在更改源代碼是不可行的。這個(gè)時(shí)候我們可以用裝飾器苛坚,如下:
username,passwd="jack","abc123"#模擬一個(gè)已登錄用戶
def decorator(func):
    def warpper(*args,**kwargs):
        Username=input("Username:").strip()
        password=input("Password:").strip()
        if username==Username and passwd==password:
            print("Authenticate Success!")
            func(*args,**kwargs)
        else:
            exit("Username or password is invalid比被!")
    return warpper

def index():
    print("welcome to the index page")
@decorator
def home():
    print("welcome to the home page")
@decorator
def bbs():
    print("welcome to the bbs page")
    return "I am the return contents"

index()
home()
bbs()

程序結(jié)果:

————————

welcome to the index page    #index頁(yè)面未驗(yàn)證直接可以登入
Username:jack
Password:abc123
Authenticate Success!           #登錄的而情形
welcome to the home page
Username:jack                      #密碼或用戶名錯(cuò)誤的情形
Password:123
Username or password is invalid色难!
————————
  • 我們注意到bbs()是有返回值的,如果我們把上述代碼的最后一句(第25行)改為“print(bbs())”之后再看看他的輸出結(jié)果:
————————

welcome to the index page
Username:jack
Password:abc123
Authenticate Success!
welcome to the home page
Username:jack
Password:abc123
Authenticate Success!
welcome to the bbs page
None                              #返回值能么成None了等缀?枷莉??

————————
  • What happened尺迂! bbs()的返回值打印出來(lái)竟然是None笤妙。怎么會(huì)這樣?這樣的話不就改變了被裝飾函數(shù)的源代碼了嗎噪裕?怎樣才能解決呢蹲盘?

    • 我們來(lái)分析一下:

    • 我們執(zhí)行bbs函數(shù)其實(shí)就相當(dāng)于執(zhí)行了裝飾器里的wrapper函數(shù),仔細(xì)分析裝飾器發(fā)現(xiàn)wrapper函數(shù)卻沒(méi)有返回值膳音,所以為了讓他可以正確保證被裝飾函數(shù)的返回值可以正確返回召衔,那么需要對(duì)裝飾器進(jìn)行修改:

username,passwd="jack","abc123"#模擬一個(gè)已登錄用戶
def decorator(func):
    def warpper(*args,**kwargs):
        Username=input("Username:").strip()
        password=input("Password:").strip()
        if username==Username and passwd==password:
            print("Authenticate Success!")
           return func(*args,**kwargs)#在這里加一個(gè)return就行了
        else:
            exit("Username or password is invalid!")
    return warpper

def index():
    print("welcome to the index page")
@decorator
def home():
    print("welcome to the home page")
@decorator
def bbs():
    print("welcome to the bbs page")
    return "I am the return contents"

index()
home()
bbs()
  • 如圖加上return就可以解決了祭陷。下面我們?cè)诳纯锤暮蟮某绦蜉敵觯?/li>
————————

welcome to the index page
Username:jack
Password:abc123
Authenticate Success!
welcome to the home page
Username:jack
Password:abc123
Authenticate Success!
welcome to the bbs page
I am the return contents   #bbs()的返回值得到了正確的返回

——-——————

好了苍凛,返回值的問(wèn)題解決了.

既然裝飾器是一個(gè)函數(shù),那裝飾器可以有參數(shù)嗎兵志?

  • 答案是肯定的醇蝴。我們同樣可以給裝飾器加上參數(shù)。比如還是上面的三個(gè)頁(yè)面函數(shù)作為例子毒姨,我們可以根據(jù)不同頁(yè)面的驗(yàn)證方式來(lái)給程序不同的驗(yàn)證哑蔫,而這個(gè)驗(yàn)證方式可以以裝飾器的參數(shù)傳入,這樣我們就得在裝飾器上在嵌套一層函數(shù) 了:
username,passwd="jack","abc123"#模擬一個(gè)已登錄用戶
def decorator(auth_type):
    def out_warpper(func):
        def warpper(*args,**kwargs):
            Username=input("Username:").strip()
            password=input("Password:").strip()
            if auth_type=="local":
                if username==Username and passwd==password:
                    print("Authenticate Success!")
                    return func(*args,**kwargs)
                else:
                    exit("Username or password is invalid弧呐!")
            elif auth_type=="unlocal":
                print("HERE IS UNLOCAL AUTHENTICATE WAYS")
        return warpper
    return out_warpper

def index():
    print("welcome to the index page")
@decorator(auth_type="local")
def home():
    print("welcome to the home page")
@decorator(auth_type="unlocal")
def bbs():
    print("welcome to the bbs page")
    return "I am the return contents"

index()
home()
bbs()

輸出:

————————

welcome to the index page
Username:jack
Password:abc123
Authenticate Success!
welcome to the home page
Username:jack
Password:abc123
HERE IS UNLOCAL AUTHENTICATE WAYS

————————
  • 可見(jiàn)闸迷,程序分別加入了第2行和第16行和中間的根據(jù)auth_type參數(shù)的判斷的相關(guān)內(nèi)容后, 就解決上述問(wèn)題了俘枫。對(duì)于上面的這一個(gè)三層嵌套的相關(guān)邏輯腥沽,大家可以在 pycharm里頭加上斷點(diǎn),逐步調(diào)試鸠蚪,便可發(fā)現(xiàn)其中的道理今阳。

  • 總結(jié)

    • 要想學(xué)好迭代器就必須理解一下三條:

    • 1.函數(shù)即變量(即函數(shù)對(duì)象的概念)

    • 2.函數(shù)嵌套

    • 3.函數(shù)式編程

原文鏈接:http://www.cnblogs.com/Akkbe-chao/p/6980332.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茅信,隨后出現(xiàn)的幾起案子盾舌,更是在濱河造成了極大的恐慌,老刑警劉巖蘸鲸,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妖谴,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)膝舅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)嗡载,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人仍稀,你說(shuō)我怎么就攤上這事洼滚。” “怎么了技潘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵遥巴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我崭篡,道長(zhǎng)挪哄,這世上最難降的妖魔是什么吧秕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任琉闪,我火速辦了婚禮,結(jié)果婚禮上砸彬,老公的妹妹穿的比我還像新娘颠毙。我一直安慰自己,他們只是感情好砂碉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蛀蜜。 她就那樣靜靜地躺著,像睡著了一般增蹭。 火紅的嫁衣襯著肌膚如雪滴某。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,578評(píng)論 1 305
  • 那天滋迈,我揣著相機(jī)與錄音霎奢,去河邊找鬼。 笑死饼灿,一個(gè)胖子當(dāng)著我的面吹牛幕侠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碍彭,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼晤硕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了庇忌?” 一聲冷哼從身側(cè)響起舞箍,我...
    開(kāi)封第一講書(shū)人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎皆疹,沒(méi)想到半個(gè)月后疏橄,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡墙基,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年软族,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刷喜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡立砸,死狀恐怖掖疮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颗祝,我是刑警寧澤浊闪,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站螺戳,受9級(jí)特大地震影響搁宾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜倔幼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一盖腿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧损同,春花似錦翩腐、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至组哩,卻和暖如春等龙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伶贰。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工蛛砰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幕袱。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓暴备,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親们豌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涯捻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)望迎,斷路器障癌,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 背景 雖然之前看過(guò)裝飾器的相關(guān)內(nèi)容,但是今天想起來(lái)辩尊,一直沒(méi)有好好總結(jié)一下涛浙,所以特地記錄下關(guān)于裝飾器的一系列用法。要...
    樓上小宇閱讀 701評(píng)論 0 3
  • 孤鴻遠(yuǎn)游人飄零, 輕語(yǔ)別離自思量轿亮。 飛絮迷離時(shí)節(jié)易疮薇, 陌上花開(kāi)君神傷。
    云高不慕閱讀 120評(píng)論 3 3
  • 9月12日,早5點(diǎn)但骨,快讀楊瀾《人工智能励七,真的來(lái)了》。 人工智能(AI:Artificial Intelligenc...
    in喜悅閱讀 595評(píng)論 0 0
  • 我一直以為奔缠,愛(ài)情是找到一個(gè)互相理解和包容的人掠抬,不必過(guò)多解釋就都懂得,優(yōu)點(diǎn)缺點(diǎn)都能喜歡校哎,好像两波,另一個(gè)自己”嵬埽可是雨女,...
    鄭正正zgy閱讀 215評(píng)論 0 0