Python-裝飾器

目錄:http://m.itdecent.cn/p/863c446364a8

裝飾器

我們談裝飾器之前先來(lái)說(shuō)說(shuō)開(kāi)放封閉原則。

開(kāi)放封閉原則:

1.開(kāi)放---對(duì)代碼的拓展開(kāi)放? ? ? ? ? 2.封閉---對(duì)源碼的修改封閉

接著我們?cè)賮?lái)談裝飾器,什么是裝飾器?

裝飾器是在不改變?cè)瘮?shù)的代碼以及調(diào)用方式的前提下,為其增加新的功能。

裝飾器完全遵守開(kāi)放封閉原則。

裝飾器同樣擁有三前提:作用域、高階函數(shù)、閉包。學(xué)會(huì)這三個(gè)東西再來(lái)學(xué)裝飾器將是水到渠成。

讓我們來(lái)做一個(gè)銀行存款的例子。

def a():

? ? print("-----存款中-----")

a()

我們現(xiàn)在有一個(gè)需求,給他增加一個(gè)密碼驗(yàn)證的過(guò)程。

def a():

? ? print("-----存款中-----")

def b():

????print("-----密碼驗(yàn)證中-----")

b()

a()

或者:

def a():

? ??b()

? ? print("-----存款中-----")

def b():

????print("-----密碼驗(yàn)證中-----")?

a()

這顯然違背了開(kāi)放封閉原則,而且造成了代碼冗余。

現(xiàn)在我們對(duì)它進(jìn)行第一次優(yōu)化:

這一次優(yōu)化是將存款函數(shù)完全放到密碼驗(yàn)證函數(shù)的保護(hù)之中,所以密碼驗(yàn)證函數(shù)要接受存款函數(shù)。

即? 我們這些優(yōu)化的思路是:使用高階函數(shù)來(lái)封裝a函數(shù),以來(lái)避免對(duì)a函數(shù)的修改。

def a():

? ? print("-----存款中-----")

def b(pwd):? # pwd = a

????print("-----密碼驗(yàn)證中-----")?

? ? pwd()? ? ?#a()??

b(a)??

這種寫法只是沒(méi)有改變?cè)瘮?shù)代碼,并且增加了新功能。但是他改變了函數(shù)的調(diào)用方式,這就不符合我們的開(kāi)放封閉原則。

我們下面進(jìn)行第二次優(yōu)化:
這次我們使用閉包來(lái)對(duì)我們的函數(shù)進(jìn)行優(yōu)化,這樣我們就可以遵循開(kāi)放封閉原則的前提下,完成功能的增加。這就是一個(gè)初級(jí)裝飾器。

def a():
? ? print("-----存款中-----")

def? b(pwd):? ?#pwd=a

????def inner():

? ? ? ? print("-----密碼驗(yàn)證中-----")

? ? ????pwd()? ? ? ? ? ? # pwd()=a()

? ? return inner? ? ? ? ? #返回inner函數(shù)

a=b(a)? ? ? ? ? ? ? #inner函數(shù)返回到這里,即a=inner

a()? ? ? ? ? #a()=inner(),這里是對(duì)inner的調(diào)用

? ? 接著我們來(lái)細(xì)致剖析一下初級(jí)裝飾器的運(yùn)行過(guò)程。

1.第一次讀取:讀取a函數(shù)的整體。

2.第二次讀取? :讀取b函數(shù)的整體

3.接著開(kāi)始執(zhí)行? a = b(a)? 將 a函數(shù) 帶入到 b函數(shù) 內(nèi),即 def b(a)? 此時(shí) 在b函數(shù)內(nèi)? pwd=a

4.因?yàn)?b函數(shù) 接受到了參數(shù),系統(tǒng)開(kāi)始執(zhí)行 b函數(shù) :b函數(shù)內(nèi)只做了兩件事情? 定義了一個(gè)

inner函數(shù),將inner函數(shù)返回。

5.? a=b(a)=inner? 因?yàn)?b(a) 返回了 inner,所以 現(xiàn)在在函數(shù)外 a=inner

6.接著執(zhí)行了? a()? 調(diào)用了 a 函數(shù)? 此時(shí)? 因?yàn)?a=inner,所以a()=inner()

7.開(kāi)始執(zhí)行? inner():? inner()函數(shù)干了兩件事情 1.print("-----密碼驗(yàn)證中-----") 2.pwd()? 因?yàn)?/p>

pwd=a? 所以 pwd() = a()

8.開(kāi)始調(diào)用最開(kāi)始的a函數(shù), 執(zhí)行 print("-----存款中-----")

9.執(zhí)行完成。

其實(shí)初級(jí)裝飾器還可以在優(yōu)化一下:

將初級(jí)裝飾器的調(diào)用語(yǔ)句換成內(nèi)置調(diào)用方式(語(yǔ)法糖)。

def b(pwd):? ? ? ? ?#這時(shí)將a傳遞給b函數(shù)中的pwd 即pwd=a

????def inner():

????????print("-----密碼驗(yàn)證中-----")

? ? ? ? pwd()

? ? return inner? ? ? ? #返回inner函數(shù)

@b? ? ?#這種寫法就是語(yǔ)法糖,他就相當(dāng)于是a=b(a)? ? ? ? #inner函數(shù)返回給了a

def a ():

? ? print("-----存款中-----")

a()? ? ? ? ?#a函數(shù)的調(diào)用相當(dāng)于inner函數(shù)的調(diào)用

?接著我們來(lái)細(xì)致剖析一下語(yǔ)法糖裝飾器的運(yùn)行過(guò)程。

1.第一次讀取 :讀取b函數(shù)的整體。

2.第二次讀取? :? ?因?yàn)樽x取到了? @b, 所以系統(tǒng)接下來(lái)的兩行看成整體,即:a = b(a)? ?def a():

3.系統(tǒng)開(kāi)始執(zhí)行? a = b(a)? 將 a函數(shù) 帶入到 b函數(shù) 內(nèi),即: def b(a)? 此時(shí) 在b函數(shù)內(nèi)? pwd=a

4.因?yàn)?b函數(shù) 接受到了參數(shù),系統(tǒng)開(kāi)始執(zhí)行 b函數(shù) :? b函數(shù)內(nèi)只做了兩件事情? 定義了一個(gè) inner函

數(shù),將inner函數(shù)返回。

5.? a=b(a)=inner? 因?yàn)?b(a) 返回了 inner,所以 現(xiàn)在在函數(shù)外 a=inner

6.最后執(zhí)行了? a()? 調(diào)用了 a函數(shù)? 此時(shí)? 因?yàn)?a=inner? a()=inner()

7.開(kāi)始執(zhí)行? inner():? inner()函數(shù)干了兩件事情 1.print("-----密碼驗(yàn)證中-----")?2.pwd()? 因?yàn)?/p>

pwd=a? 所以 pwd() = a()

8.開(kāi)始調(diào)用最開(kāi)始的a函數(shù), 執(zhí)行?print("-----存款中-----")

9.執(zhí)行完成。

裝飾器的返回值

現(xiàn)在我們又有了新的需求,我們想要獲取存款的過(guò)程,而不是將存款過(guò)程直接打印出來(lái),這就需要我們的存款函數(shù)a有返回值,現(xiàn)在修改如下:

def b(pwd):

? ? def inner():

? ? ? ? print("-----密碼驗(yàn)證中-----")

? ? ? ? r=pwd()? ? ? ? ?#這里本來(lái)是直接調(diào)用a函數(shù),現(xiàn)在將他修改為接收a函數(shù)的返回值

? ? ? ? return r? ? #這里將函數(shù)a的返回值返回給最后一句a的調(diào)用

? ? return inner? ?

@b? ?

def a ():? ? ? ? ? ??

????return "-----存款中,存款金額為200-----"? ? ? #a函數(shù)的返回值

print(a())? ? ? #這里是a的調(diào)用,同時(shí)是a函數(shù)返回值的最后一站


帶參裝飾器

上面是我們普通裝飾器,不能夠傳遞參數(shù),靈活性較差,所以就有了我們的帶參裝飾器,讓我們?cè)谏厦娴睦友a(bǔ)充一個(gè)新功能可以顯示我們的存款金額。

def b(pwd):? ? ? ? ?#這時(shí)將a傳遞給b函數(shù)中的pwd 即pwd=a(money)

????def inner(*args,**kwargs):? #讓inner使用不定長(zhǎng)參數(shù)來(lái)接收a的參數(shù)? ?*args=(500)

????????print("-----密碼驗(yàn)證中-----")

? ? ? ? pwd(*args,**kwargs)? ? ? ? ? ? #在這里將500賦給pwd,相當(dāng)于是a(500)

? ? return inner? ? ? ? #返回inner函數(shù)

@b? ? ?#這種寫法就是語(yǔ)法糖,他就相當(dāng)于是a=b(a)? ? ? ? #inner函數(shù)返回給了a

def a (money):? ? ? ? ?#此時(shí)money=500

? ? print("-----存款中,存款金額為{}-----".format(money))

a(500)? ? ? ? ?#a函數(shù)的調(diào)用相當(dāng)于inner函數(shù)的調(diào)用

運(yùn)行結(jié)果為:

-----密碼驗(yàn)證中-----

-----存款中,存款金額為500-----

帶參語(yǔ)法糖?

現(xiàn)在我們?cè)俳o他美化一下,在密碼驗(yàn)證中之后輸出一排*,同時(shí)我們又要遵守我們的開(kāi)放封閉原則,所以要使用帶參語(yǔ)法糖,修改如下:

def c(char):? ? ? ? ? ? ? ?#這時(shí)將*傳遞給c函數(shù)的char即char=*

????def b(pwd):? ? ? ? ?#這時(shí)將a傳遞給b函數(shù)中的pwd 即pwd=a

????????def inner():

????????????print("-----密碼驗(yàn)證中-----")

????????????print(char*15)? ?#char = “*”? 輸出 ***************

? ? ? ????? pwd()? ? ? ? ? ? ? ? ? ? #pwd = a? ?這里調(diào)用了a函數(shù) 輸出? ?-----存款中-----

? ????? return inner? ? ? ? ? ? ? #將inner函數(shù)返回給a=b(a)

????return b? ? ? ? ? ? ? ? ? ? ? ? ?#將b函數(shù)返回給a=c(*)

@c("*")? ? ? ? ? ? #在這里相當(dāng)于執(zhí)行了兩條語(yǔ)句 a=c(*)? ?a=b(a)? ?這里a接受到了 兩個(gè)返回值,后一個(gè)返回值? innner? 覆蓋前一個(gè)返回值 b? 即? a=inner

def a ():

? ? print("-----存款中-----")

a()? ? ? ? ?#a函數(shù)的調(diào)用相當(dāng)于inner函數(shù)的調(diào)用

運(yùn)行結(jié)果為:

-----密碼驗(yàn)證中-----

***************

-----存款中-----

標(biāo)準(zhǔn)版的裝飾器

def wrapper(f):

? ? def inner(*args,**kwargs):

? ? ? ? f(*args,**kwargs)

? ? return inner

設(shè)計(jì)一個(gè)裝飾器,顯示函數(shù)運(yùn)行的時(shí)間。 輸出格式為(函數(shù)名,時(shí)間)

import time

def timmer(f):

? ? def inner ():

? ? ? ? start_time=time.time()

? ? ? ? f()

? ? ? ? end_time=time.time()

? ? ? ? print(f,end_time-start_time)

? ? return inner

@timmer? fun=timmer(fun)

def fun():

? ? time.sleep(2)

? ? print("Welcome to China")

fun()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容